Table of Contents
- The Science
- Overview: The analytics pipeline
- Heart-Rate Variability (HRV)
- RMSSD — the root-mean-square of successive differences
- Cleaning: removing noise and ectopic beats
- Other HRV metrics
- Recovery Scoring
- The 0–100 composite
- Baseline normalization: z-scores
- The logistic squash to 0–100
- Bands
- Cold-start: when you don't have a baseline yet
- Strain Scoring
- The 0–21 cardiovascular load scale
- Step 1: Heart-Rate Reserve (HRR)
- Step 2: TRIMP accumulation
- Step 3: Logarithmic compression to 0–21
- HRmax estimation
- Sleep Staging
- The 4-class hypnogram
- Stage 0: Gravity-based sleep/wake spine
- Stage 1: Cardiorespiratory features per 30-second epoch
- Stage 2: Percentile-band classifier
- Stage 3: Smoothing and physiology re-imposition
- Outputs
- Baselines: Your personal rolling averages
- Workouts and Exercise Detection
- Interactive: Correlations, Behavior Effects, and Comparisons
- Advanced: Readiness and Training Load
- Illness and Strain Early-Warning
- Design principles & honesty notes
- Approximate by design
- Deterministic and testable
- Robust statistics
- Cold-start honesty
- Not a medical device, not medical advice
- References and further reading
- See also
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
The Science
NOOP computes recovery, strain, HRV, and sleep locally on your device using transparent, published physiological methods. Every metric is an approximation of common exercise-science and cardiology literature — not a reproduction of any proprietary algorithm, and not a medical device or medical advice.
Not affiliated with WHOOP. NOOP is independent interoperability software for your own device and your own data. The methods described here are grounded in peer-reviewed literature and are the same class of tools used in sports-science research labs — they are estimates, not clinical measurements. Do not use them to diagnose, treat, or make health decisions. Consult a qualified professional.
Overview: The analytics pipeline
All mathematics in NOOP is pure, deterministic, and database-free: same inputs always produce the same outputs, which makes every analyzer straightforward to unit-test. The analytics live in the cross-platform StrandAnalytics Swift package, and they run on-device against:
- Live BLE streams (heart rate, R-R intervals, respiration, gravity/accelerometer) arriving from the strap in real time.
- Imported history from WHOOP CSV exports and Apple Health exports.
- Historical offload from the strap's on-device store (~14 days) each time you connect.
The computed metrics are persisted in SQLite under the "<deviceId>-noop" source, but WHOOP's own imports (when you import a CSV) always take precedence — NOOP's approximations win only for data WHOOP doesn't cover.
Heart-Rate Variability (HRV)
RMSSD — the root-mean-square of successive differences
HRV is the beat-to-beat variation in your heart rate, measured as R-R intervals (the time between consecutive heartbeats in milliseconds). NOOP computes RMSSD — the classic Task Force (1996) metric:
RMSSD = sqrt( (1/(N-1)) · Σ(NN[i+1] − NN[i])² )
Where NN is a sequence of normal R-R intervals (in ms), and each term is the squared difference between consecutive intervals.
Why RMSSD? It captures the parasympathetic tone (vagal activity) of your autonomic nervous system — the "rest and digest" branch that keeps you calm and recovered. Higher RMSSD means more variability, which usually correlates with better recovery and lower stress.
Cleaning: removing noise and ectopic beats
Raw R-R data can contain artifacts — missed beats, extra beats (ectopics), electrical noise. NOOP applies a deterministic cleaning pipeline:
- Range filter — drop intervals outside the plausible
[300, 2000]ms band (~30–200 bpm). - Ectopic rejection (Malik et al., 1989) — drop any beat deviating more than 20% from a local median over a 5-beat centered window. This is a simpler substitute for the Kubios algorithm (which isn't available on-device) and catches physiologically impossible jumps.
- Sufficiency gate — require at least 20 clean intervals before returning a result; otherwise return
nilrather than guessing.
Honest substitution: The reference method used neurokit2's Kubios/Lipponen–Tarvainen artifact classifier, which requires external Python libraries. NOOP substitutes the classical Malik local-median rule — fully deterministic, works on-device, and achieves the same intent: removing impossible beat-to-beat swings before computing HRV.
Other HRV metrics
- SDNN — the sample standard deviation of NN intervals (Task Force 1996). A broader measure of variability over the whole recording.
- pNN50 — the percentage of successive differences > 50 ms. A marker of parasympathetic dominance.
Recovery Scoring
The 0–100 composite
NOOP's recovery score is an HRV-dominant, baseline-normalized composite that blends several drivers into a single 0–100 number. It is explicitly approximate — the key insight is that recovery is personal: your good recovery looks different from someone else's, so comparing you to yourself matters more than comparing to a population average.
| Driver | Direction | Weight |
|---|---|---|
| HRV vs your baseline | Higher → better recovery | 60% (dominant) |
| Resting HR vs your baseline | Lower → better | 20% |
| Respiration rate vs your baseline | Lower → better | 5% |
| Sleep performance | Better sleep → better recovery | 15% |
Baseline normalization: z-scores
Each metric is standardized against your personal baseline using a robust z-score:
z = (value − mean) / (1.253 · spread)
The 1.253 factor converts an EWMA mean-absolute-deviation (MAD) into an approximate Gaussian standard deviation (E[|X−μ|] ≈ σ / 1.253). For "lower is better" metrics (resting HR, respiration), the z is inverted so high values still push recovery down.
Sleep performance is centered directly: (sleepPerf − 0.85) / 0.12 — anchoring on 85% efficiency as a typical target.
The logistic squash to 0–100
The weighted-mean z-score is then squashed to 0–100 with a logistic curve:
score = 100 / (1 + exp(−k · (z − z0)))
where k = 1.6, z0 = −0.20
The z = 0 point (your personal baseline, across all metrics) maps to approximately 58% — matching WHOOP's published population-average recovery. This anchoring means: when your HRV, RHR, and respiration are all exactly at your typical baseline, your score is ~58%, not 50%. Z = +2 drives toward 95%; Z = −2 drives toward 5%.
Bands
| Band | Range |
|---|---|
| Red (needs recovery) | < 34 |
| Yellow (balanced) | 34–67 |
| Green (ready to push) | ≥ 67 |
Cold-start: when you don't have a baseline yet
If your HRV baseline isn't trustworthy yet (fewer than 4 valid nights), NOOP returns nil rather than a fabricated number. This is intentionally honest — more painful than a guess, but more truthful. Callers can fall back to the population mean (58%), but the screen flags it as provisional.
Once you have 4+ nights, the baseline becomes "provisional" (4–13 nights), then "trusted" (14+).
Strain Scoring
The 0–21 cardiovascular load scale
Strain is the cumulative physiological load from exercise during a day. NOOP uses a published, scalable method: the Heart-Rate Reserve (Karvonen) intensity model combined with TRIMP (Training Impulse) accumulation, mapped to a 0–21 logarithmic scale.
Step 1: Heart-Rate Reserve (HRR)
HRR = HRmax − Resting HR
%HRR = (HR − RHR) / HRR × 100, clamped [0, 100]
This expresses your current heart rate as a fraction of your reserve — what percentage of your maximum capacity you're using right now.
Step 2: TRIMP accumulation
NOOP supports two methods; the default is Edwards (1993):
Edwards 5-zone summation (default)
Each heart-rate sample contributes its zone weight multiplied by duration:
| Zone | %HRR range | Weight |
|---|---|---|
| Zone 1 | < 50% | 1 |
| Zone 2 | 50–60% | 2 |
| Zone 3 | 60–70% | 3 |
| Zone 4 | 70–80% | 4 |
| Zone 5 | ≥ 80% | 5 |
TRIMP = Σ(duration_in_zone × weight)
Banister exponential (alternative)
An older but well-cited model: duration × x × 0.64 × e^(b·x) where x = %HRR/100 and b = 1.92 (men) or 1.67 (women).
Step 3: Logarithmic compression to 0–21
strain = 21 · ln(TRIMP + 1) / ln(D)
where D = 7201
The denominator D is calibrated so that the Edwards daily ceiling — maximum zone weight (5) sustained for 24 hours = 5 × 1440 = 7200 — maps to exactly 21.0. This makes 21 a true physiological ceiling for the day: you'd need to stay in zone 5 all night to reach it.
HRmax estimation
NOOP estimates your maximum heart rate using two methods:
- Observed (if you have ≥600 HR samples on record): the 99.5th percentile of your recorded HR, used as the starting point.
- Tanaka (2001):
HRmax = 208 − 0.7 × age. A gender-independent population estimate that serves as a floor — if Tanaka is higher than your observed max, Tanaka is used (to avoid underestimating if you haven't hit your true max yet). - Manual override: you can set your own max HR in Settings.
If you supply no age and have no data, the scorer returns nil.
Sleep Staging
The 4-class hypnogram
NOOP detects sleep/wake and attempts to classify four stages: Wake, Light, Deep (slow-wave), and REM (rapid eye movement). This is the same classification used in clinical sleep studies, but without EEG — the ceiling for 4-class accuracy (without brain waves) is ~65–73% epoch-by-epoch agreement (Walch et al., 2019).
Honest hedging: These stages are approximations, not validated against polysomnography (PSG, the clinical gold standard). Light/deep separation is the weakest link. Deep-minute estimates are the least reliable output. Use these trends over time, not individual-night predictions.
Stage 0: Gravity-based sleep/wake spine
The foundation is stillness. NOOP tracks the magnitude of gravity changes (accelerometer) and identifies periods where motion is minimal:
- Per-sample motion proxy = L2 norm of the gravity-vector change from the previous sample.
- A sample is "still" if this delta is < 0.01 g.
- Roll forward in a 15-minute window: if ≥70% of samples are still, the center is marked "sleep".
- Contiguous still runs ≥60 minutes (merging gaps < 15 min) are candidates.
- HR confirmation: the run's mean HR must be ≤1.05× the day's median HR (the sleep baseline). This rejects false sleep from long stillness at rest.
Additionally, NOOP computes the te Lindert 30-second Cole–Kripke sleep index per epoch as a cross-check:
SI = 0.001 · Σ w_i · A_i (sleep iff SI < 1)
weights = [106, 54, 58, 76, 230, 74, 67]
(This is a classical 7-channel electroencephalographic index adapted for actigraphy.)
Stage 1: Cardiorespiratory features per 30-second epoch
Over a rolling 5-minute window, NOOP extracts:
- Mean heart rate — averaged over the window.
- HR variability (Walch difference-of-Gaussians) — two Gaussian convolutions of HR (σ = 120 s and 600 s) subtracted; this captures medium-scale HRV oscillations.
- RMSSD and SDNN — computed from range-filtered R-R intervals (cleaned via
HRVAnalyzer). - Respiration rate and RRV — extracted from the raw 1 Hz respiration channel via a peak detector (detrend → find local maxima ≥2 s apart → bin into breath intervals 1.5–12 s → median interval → rate = 60 / interval).
Omission: Frequency-domain HRV (high-frequency HRV, LF/HF ratio) is not computed because FFT and signal processing require libraries unavailable on-device. The parasympathetic-tone signal is RMSSD only. The respiration peak-finder is a faithful port of the reference method (which also avoided scipy).
Stage 2: Percentile-band classifier
The session's sleep-period epochs (Cole–Kripke = sleep) define reference distributions for each feature. Each epoch is then classified by comparing its features to these percentiles:
| Class | Rule |
|---|---|
| Wake | Sustained motion (≥15% of epoch) AND activated cardiac (high HR or high DoG-HR), OR no HR data |
| Deep | Still (≤10% motion) AND high parasympathetic tone (RMSSD ≥70th percentile) AND low HR (≤25th percentile) AND regular respiration |
| REM | Still body AND activated cardiac AND irregular respiration (RRV ≥65th percentile); fallback requires both cardiac signals if respiration is unavailable |
| Light | Everything else (the default) |
Stage 3: Smoothing and physiology re-imposition
- 5-epoch median smoothing of the label sequence — smooths out single-epoch noise.
- No REM in the first 15 minutes — REM sleep doesn't appear right at sleep onset; demote to light.
- No deep after the first third — deep sleep is front-loaded; demote later deep epochs to light.
- Force pre-onset and post-final-wake to
wake.
Consecutive same-stage epochs are merged into segments tiling the session.
Outputs
- SleepSession: start, end, in-bed efficiency (
asleep / in-bed), per-session resting HR, average HRV (RMSSD over 5-min windows), and a reconstructed hypnogram (stage durations). - AASM-style roll-up: time-in-bed (TIB), total sleep time (TST), sleep-period time (SPT), sleep onset latency (SOL), REM latency, wake after sleep onset (WASO), efficiency, disturbances, and deep/REM/light minutes.
Baselines: Your personal rolling averages
Recovery and strain scoring depend on personal baselines — your own typical HRV, resting HR, and respiration — so NOOP learns them as you wear the strap. Two interchangeable approaches produce the same result:
Winsorized EWMA (production)
A robust, recency-weighted center with exponential-moving-average spread tracking:
- Half-life → smoothing factor: HRV center uses 14-night half-life; spread uses 21-night (slower, more conservative).
- Sanity gate: values outside the per-metric range (e.g., HRV 5–250 ms) are skipped and held.
- Hard outlier rejection: values > 5× spread away are recorded but not folded into the baseline.
- Winsor clamp: fold only within ±3× spread of the current baseline, so a single exceptional night can't yank the center. The spread itself uses the unclamped deviation so real physiological change is still tracked.
let clamped = max(lo, min(hi, value)) // ±3·spread
let newBaseline = lb * clamped + (1 - lb) * state.baseline
let newSpread = max(floorSpread, ls * abs(value - newBaseline) + (1 - ls) * state.spread)
Trailing-window mean (auditable alternative)
Plain mean and sample SD (ddof = 1) over the last 30 valid nights. The σ floor is applied and converted back to absolute-deviation space so the two methods recover the same Gaussian σ.
Baseline status lifecycle
| Status | Condition |
|---|---|
calibrating |
Fewer than 4 valid nights (no score yet) |
provisional |
4–13 valid nights (usable, higher uncertainty) |
trusted |
14+ valid nights |
stale |
Trusted but no update for > 14 days |
Workouts and Exercise Detection
Automatic detection from HR and motion
NOOP detects exercise periods without manual logging — a sustained window (≥5 minutes) where both gates hold:
- Elevated HR: above
RHR + 15 bpm(the resting HR of your session + margin). - Sustained motion: gravity-derived intensity (10-second trailing mean) above 0.20.
Active samples are grouped into runs, merged if gaps are < 150 seconds, then qualified: ≥50% of the bout must be in Edwards zone 2+ to count.
Metrics per bout
Per workout, NOOP reports:
- Average and peak heart rate.
- Duration, Edwards zone distribution, mean %HRR.
- Strain (computed via the same StrainScorer as daily strain).
- Calories (see below).
Calories: Keytel + revised Harris–Benedict
Per-second blend with sex-specific coefficients:
- Below
RHR + 0.30 × HRR: use revised Harris–Benedict (resting metabolic rate). - Above: use Keytel (2005) active expenditure model, sex-specific.
The blend provides a smooth transition. Approximate — not laboratory calorimetry.
Interactive: Correlations, Behavior Effects, and Comparisons
NOOP provides three on-device interrogation engines for your own data:
Correlation analysis (Pearson r)
r = Σ(x−x̄)(y−ȳ) / sqrt( Σ(x−x̄)² · Σ(y−ȳ)² )
slope = Σ(x−x̄)(y−ȳ) / Σ(x−x̄)²
t-statistic = r · sqrt( (n−2) / (1−r²) )
p-value ≈ 2·(1 − Φ(|t|)) [normal approximation]
- Returns
nilfor fewer than 3 pairs or zero variance. - The normal approximation slightly understates p for small n (true Student-t tails are heavier), but is fully deterministic on-device.
- Supports lagged correlations (e.g., today's strain vs tomorrow's recovery) via day-aligned and shifted series.
Behavior effects (Welch t-test)
Splits days where you logged a behavior (Alcohol, Meditation, etc.) from days you didn't, and compares an outcome (Recovery, HRV, Sleep) between groups:
sp = sqrt( ((n1−1)·s1² + (n2−1)·s2²) / (n1+n2−2) ) [pooled SD]
d = (m1 − m2) / sp [Cohen's d]
t = (m1 − m2) / sqrt(s1²/n1 + s2²/n2) [Welch t]
significantrequiresp < 0.05andmin(nWith, nWithout) ≥ 5(guards against spurious significance from a handful of days).- Results are ranked by effect size (|d|), significant findings first.
- Plain-English summary: "On days you logged 'Alcohol', Recovery was 12% lower (avg 61 vs 69, n=140 vs 498)."
Period comparison
Month-over-month, quarter-over-quarter, or custom window comparison of a single metric:
SeriesStat: mean, median, min, max, sample SD (ddof=1), n, and OLS slope-per-day
PeriodComparison: signed delta, % change, direction (-1/0/+1)
Advanced: Readiness and Training Load
NOOP's Readiness screen synthesizes several sports-science signals from your own history into a single readout ("Primed / Balanced / Strained / Run down"):
Drivers
- HRV vs baseline (Plews/Buchheit) — parasympathetic tone shift.
- Resting-HR drift (Lamberts) — orthostatic stress rising.
- Respiratory-rate drift — autonomic load indicator.
- Acute:chronic workload ratio (ACWR) (Gabbett) — training volume balanced against your typical load.
- Training monotony (Foster) — variability of your training over the past week.
All signals are z-scored against your own baselines and combined with a logistic curve into a single readiness band. Approximate, not medical advice — this is the same class of analysis used in sports-science labs for coaching, not a clinical screen.
Illness and Strain Early-Warning
NOOP watches for the classic early-illness/elevated-strain signature on-device by comparing your last ~2 days against a ~28-day baseline (ending 3 days ago, to avoid contamination):
| Signal | Baseline shift | Anomaly condition |
|---|---|---|
| Resting HR ↑ | Elevated | Recent mean ≥ baseline mean + 5 bpm |
| HRV ↓ | Depressed | Recent mean ≤ baseline mean × 0.80 (−20%) |
| Skin temp ↑ | Elevated | Recent mean deviation ≥ +0.6 °C |
| Respiration ↑ | Elevated | Recent mean ≥ baseline mean + 1.5 bpm |
A banner appears only when two or more anomalies fire together (e.g., RHR up + HRV down + skin-temp up), the classic early-illness signature. Requires at least 14 days of history.
Important: This is a wellness nudge from your own baselines, not a clinical screen. It is informational only — not medical advice, not a diagnosis.
Design principles & honesty notes
Approximate by design
Every metric — recovery, strain, sleep stages, workout intensity, calories — is an explicit approximation of published methods. The source code documents exactly where it substitutes (Malik local-median instead of Kubios, RMSSD-only parasympathetic tone instead of frequency-domain HRV, normal-approximation p-values instead of Student-t tabled values).
Deterministic and testable
No randomness, no wall-clock dependence inside the math, no database access. Same inputs always produce the same outputs, making the whole package unit-testable against fixed vectors.
Robust statistics
- Z-scores use EWMA mean-absolute-deviation (
×1.253to Gaussian σ); rounding resistant. - Resting HR uses 5-minute bin minima; single-beat dips are rejected.
- Heart-rate display uses windowed medians; outliers don't spike the plot.
- Baselines use Winsor clamping; a single exceptional night doesn't yanked the center.
Cold-start honesty
When a baseline isn't trustworthy yet, the scorer returns nil rather than a fabricated number. More painful than guessing, but more truthful.
Not a medical device, not medical advice
None of this is diagnostic or medically actionable. HRV, recovery, strain, sleep stages, and the illness early-warning are wellness approximations, not clinical measurements. Consult a qualified professional for health decisions.
References and further reading
The methods implemented in NOOP draw from peer-reviewed literature:
- Task Force (1996). Heart rate variability: standards of measurement, physiological interpretation and clinical use. Circulation, 93(5), 1043–1065.
- Karvonen, M. J. (1957). Effects of vigorous exercise on the heart. Work and Stress, 9, 3–9.
- Edwards, S. (1993). The heart rate monitor book. Polar Electro (Oy).
- Banister, E. W. (1991). Modeling elite athletic performance. In Physiological testing of the high-performance athlete (pp. 403–424). Human Kinetics.
- Tanaka, H., Monahan, K. D., & Seals, D. R. (2001). Age-predicted maximal heart rate revisited. Journal of the American College of Cardiology, 37(1), 153–156.
- Keytel, L. R., et al. (2005). Prediction of energy expenditure from heart rate monitoring during submaximal exercise. Journal of Sports Sciences, 23(3), 289–297.
- Walch, O., et al. (2019). Sleep stage prediction with raw acceleration and photoplethysmography heart rate data derived from a consumer wearable device. Sleep, 42(12), zsz180.
- Plews, D. J., Laursen, P. B., & Buchheit, M. (2017). Training adaptation and heart-rate variability: A systematic review. Sports Medicine, 47(8), 1521–1538.
- Gabbett, T. J. (2016). The training-injury prevention paradox: should athletes be training smarter and harder? British Journal of Sports Medicine, 50(5), 273–280.
- Foster, C., et al. (1995). A new approach to monitoring exercise training. Journal of Strength and Conditioning Research, 12(3), 109–115.
See also
- Features — what NOOP can show you on screen
- How NOOP Works — the architecture and data pipeline
- Privacy and Security — how your data stays on your device
- Strap Support and Pairing — which WHOOP models work and how to pair them
- Troubleshooting — common questions and fixes
Home
Get started
Tutorials
- Tracking a Workout
- Recovery, Strain & Readiness
- Automations
- Breathe & Intervals
- Importing History
- AI Coach
- Widget & Notifications
- Reading Your Sleep
- Explore & Compare
Reference
Project
NOOP is an independent, unofficial, non-commercial interoperability project — not affiliated with, endorsed by, or sponsored by WHOOP, Inc. "WHOOP" is a trademark of WHOOP, Inc., used nominatively. Works only with a device you own; not a medical device; every metric is an approximation, not medical advice. · Privacy and Security · Donations · Releases