Back to Knowledge Base

Knowledge

How OpenSpiro calculates VO2 (and what to watch out for)

A long read for VO2 analyzer nerds: the Haldane transformation, wet- vs dry-basis bookkeeping, how OpenSpiro calculates VO2 with the OSM1, and the sensor realities that make or break your readings.

A VO2 number on a screen looks deceptively simple: 3,200 mL/min, 45 mL/kg/min, done. In reality, that single value rests on a chain of conventions and assumptions that vary by device, by sensor, and by ambient conditions. Get any link in the chain wrong and your VO2 can drift 20–50% without anything looking obviously broken. This article walks through what OpenSpiro actually does, why the sensor decides which convention is correct, and the practical realities of getting trustworthy numbers.

The fundamental formula: Haldane mass balance

VO2 isn't measured directly. What gas analyzers actually measure are: how much air came out of you (volume), and what fraction of that air was O2 and CO2. To turn those into "millilitres of oxygen per minute consumed" you need to know how much air went in — and that's where the Haldane transformation comes in.

Nitrogen is metabolically inert: the body neither produces nor consumes it. So the nitrogen flux in equals the nitrogen flux out. With expired O2 (FEO2) and CO2 (FECO2) fractions known, and inspired air at known fractions (FIO2 ≈ 0.2095, FICO2 ≈ 0.0004), you can derive the inspired volume from the expired volume:

Haldane ratio = FEN2 / FIN2 = (1 − FEO2 − FECO2) / (1 − FIO2 − FICO2)
VO2 = VE × (FIO2 × Haldane − FEO2)
VCO2 = VE × (FECO2 − FICO2 × Haldane)

Easy on paper. The trouble starts with what VE and the gas fractions actually mean physically.

STPD, wet vs dry: the bookkeeping problem

Volume isn't volume. Air at body temperature, fully saturated with water vapor (BTPS), occupies more space than the same molecules at 0 °C, 1013 hPa, dry (STPD). To compare metabolic rates across labs and conditions, every analyzer corrects volumes to STPD. The standard correction is:

STPD = (P_amb / 1013.25) × (273.15 / T_K) × (1 − PH2O / P_amb)

The first two terms convert temperature and pressure. The last term subtracts water vapor — which only makes sense if you're trying to count dry molecules. Whether you apply it depends on whether your O2 and CO2 sensors see wet or dry gas:

  • Dry-basis sensors (e.g. paramagnetic O2 cells with a sample-drying line): the sensor's FEO2 is already the fraction of dry expired air. Apply the full STPD correction including the water-vapor term, and use the textbook Haldane formula above.
  • Wet-basis sensors (most galvanic O2 cells, NDIR CO2 sensors without drying): the sensor reports the fraction of wet expired air, where water vapor still occupies space. Now the bookkeeping has to be consistent: keep everything on a wet basis. The FIO2 of inspired wet ambient air is 0.2095 × (1 − PH2O_amb/P_amb), the Haldane denominator includes water vapor explicitly, and the volume STPD correction omits the water-vapor term (it's already accounted for on the gas side).

Both conventions are physically correct in isolation. Mix them — apply a textbook dry-basis formula to a sensor that reads wet — and you'll inflate VO2 by roughly 5–20% depending on conditions. The reverse mistake — wet-basis bookkeeping on fractions that are already dry — removes water vapor twice and under-reports VO2 by a similar margin. Water vapor has to enter the chain exactly once.

How OpenSpiro calculates VO2 with the OSM1

OpenSpiro works with the OSM1, our own analyzer. Its gas sensor combines an optical O2 sensor with an NDIR CO2 sensor and reports dry-gas fractions: the O2 and CO2 values are already humidity-compensated, i.e. volumetric fractions after the water-vapor component has been removed. That settles the convention — the OSM1 math stays on a dry basis throughout. The active calculation model is shown as a badge next to the session timer and is recorded with every saved session.

Dry-basis, exhalation-only Haldane

The OSM1 uses expired volume only. Inspired volume measured at the mask is easily biased by small leaks, so OpenSpiro reconstructs it via the Haldane transformation against dry ambient air (FIO2 = 20.95%, FICO2 = 0.04%):

FIN2_dry = 1 − 0.2095 − 0.0004 = 0.7901
V_in     = V_out · (1 − FEO2 − FECO2) / FIN2_dry
VO2      = V_in · 0.2095 − V_out · FEO2
VCO2     = V_out · FECO2 − V_in · 0.0004

V_out is the exhaled volume corrected to dry STPD.

Dry-STPD volume correction

Because the gas fractions are already dry, water vapor appears exactly once in the whole chain: in the conversion of the measured exhaled volume (ATPS) to dry STPD. The exhalate is treated as saturated at the measured gas temperature:

SVP(T)  = 6.1 · exp(17.27 T / (T + 237.3))                          // hPa, Magnus
V_STPD  = V_ex · (P_amb − SVP(T_gas)) / 1013.25 · 273.15 / (273.15 + T_gas)

No humidity term on the gas side, no wet-corrected FIO2 — adding either would count water vapor twice.

Sensor realities (the things that actually move your numbers)

The math is the easy part. Sensor behaviour, room conditions, and how the mask sits on your face contribute far more variance than the choice of formula. A few practical realities:

Sensor drift. Galvanic O2 cells slowly lose signal as their electrolyte depletes (typical lifetime 1–2 years of regular use). NDIR CO2 sensors drift with temperature and ambient pressure. If your analyzer supports calibration, run it before every session — otherwise expect a slow upward bias in VO2 over the sensor's life.

Sensor technologies. Worth knowing what's inside the box you bought:

  • O2 — Galvanic cells (cheap, drift-prone, used in most portable units), paramagnetic (lab-grade, expensive), zirconia (fast, runs hot), optical / luminescence-quenching (driftless, fast response, no consumable parts — increasingly common in modern lab analyzers and next-generation portables).
  • CO2 — NDIR (the standard for portable units; fast, low drift), Severinghaus electrodes (lab-only).
  • Flow — Pneumotachograph (resistance-based, calibration-sensitive), differential pressure (common in portable analyzers, very sensitive to drafts), ultrasonic (expensive but essentially driftless).

Each technology trades off response time, drift, and absolute accuracy. The numbers your screen shows reflect whatever's in your device — software can't fix bad sensor data.

Drafts and air movement. Portable analyzers see breath-scale volume and pressure changes. Run sessions in a closed indoor room without fans or open windows. A direct breeze on the mask creates phantom flow on the sensor and pulls ambient air past the mask seal into the exhaled gas — VO2 will drift upward by 5–15% with even moderate cross-breeze. Compact portable analyzers with differential-pressure flow sensors are especially affected because they read tiny pressure differences. If you can feel air moving on your face, the calculation can't recover from it.

Humidity and water vapor. Exhaled air is fully saturated at ~37 °C, ~100% RH. Ambient air is usually drier (20–60% RH). Water vapor takes up "space" and dilutes the measured O2 and CO2 fractions. Get this correction wrong and VO2 swings by 5–20%. The calculation has to handle this consistently — see the OSM1 section above.

Missing sensors. Not every analyzer measures every quantity. Some report only ambient temperature and humidity, not the conditions of the exhaled gas; in that case, calculations have to substitute physiological estimates, since exhaled gas is essentially body-temperature and saturated regardless. The closer the measurement sits to the actual exhaled gas, the fewer assumptions the math needs.

Masks and dead space. The mask between your face and the analyzer adds dead space — air that gets rebreathed instead of refreshed. Standard mouthpieces add ~30 mL; full-face masks add 100–250 mL. More dead space inflates apparent CO2 at low ventilation and slightly suppresses VO2. A well-fitting mask matters more than dead space — leaks are worse, because ambient air sneaks in undetected and pulls O2/CO2 fractions toward atmospheric values, which inflates VO2 in a way no calculation can correct for.

Calibration matters in two flavours. Span/zero on gas sensors — most devices auto-calibrate against ambient air at startup, fixing the reference at "20.93% O2, 0.04% CO2". If ambient air isn't actually that, your readings will be biased. Volume calibration — the flow sensor needs a 3-litre syringe pump or factory-set characterisation. Volume error scales VO2 directly: a 5% volume error becomes a 5% VO2 error. Without good calibration, expect day-to-day variability of ±5%. Trends across weeks are still meaningful; single-session absolute numbers, less so.

A note on RER smoothing

OpenSpiro deliberately avoids very long RER smoothing windows. A window of several hundred breaths spans far longer than RER's metabolic dynamics, so during a graded test the displayed RER would lag the true value by minutes — long enough to miss the lactate-threshold inflection altogether.

OpenSpiro uses a Median(5) + EMA smoother (≈30 seconds, 5–10 breaths), which preserves transient detail while still suppressing single-breath sensor noise. Single-breath RER may briefly show values above 1.0 during high-intensity work as a result — that's expected and physiologically real, not an artifact.

Why the transparency matters

Every saved session in OpenSpiro records which calculation model produced its readings, and CSV / JSON exports tag the model and the OpenSpiro version. If you ever need to defend a number — to a coach, a sports scientist, or your future self three years from now — the math is fully traceable. The full formula reference is built into the app under the Help tab.

References & further reading

  1. New methods for calculating metabolic rate with special reference to protein metabolism — Weir JB de V, J Physiol 1949
  2. Calculation of substrate oxidation rates in vivo from gaseous exchange — Frayn KN, J Appl Physiol 1983
  3. A new method for detecting anaerobic threshold by gas exchange — Beaver, Wasserman, Whipp, J Appl Physiol 1986
  4. Improved Magnus form approximation of saturation vapor pressure — Alduchov & Eskridge, J Appl Meteorol 1996
  5. Standardisation of spirometry — Miller, Hankinson, Brusasco et al., Eur Respir J 2005