The goal of whippr
is to provide a set of tools for manipulating gas exchange data from cardiopulmonary exercise testing.
Why whippr
?
The name of the package is in honor of Prof. Brian J Whipp and his invaluable contribution to the field of exercise physiology.
Installation
You can install the development version of whippr
from Github with:
# install.packages("remotes")
remotes::install_github("fmmattioni/whippr")
Use
Read data
library(whippr)
## example file that comes with the package for demonstration purposes
path_example <- system.file("example_cosmed.xlsx", package = "whippr")
df <- read_data(path = path_example, metabolic_cart = "cosmed")
df
#> # Metabolic cart: COSMED
#> # Data status: raw data
#> # Time column: t
#> # A tibble: 754 × 119
#> t Rf VT VE VO2 VCO2 O2exp CO2exp `VE/VO2` `VE/VCO2` `VO2/Kg`
#> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
#> 1 2 8.08 1.19 9.60 380. 301. 185. 52.9 25.3 31.9 4.58
#> 2 4 23.2 0.915 21.2 864. 665. 141. 40.8 24.5 31.9 10.4
#> 3 8 15.6 2.11 32.9 1317. 1075. 325. 97.2 25.0 30.6 15.9
#> 4 11 20.6 1.18 24.4 894. 714. 188. 49.2 27.3 34.1 10.8
#> 5 14 23.3 0.947 22.1 822. 647. 150. 39.4 26.9 34.1 9.90
#> 6 18 14.7 2.28 33.6 1347. 1126. 351. 108. 24.9 29.8 16.2
#> 7 23 11.2 2.32 26.1 980. 848. 364. 107. 26.6 30.7 11.8
#> 8 28 13.2 2.18 28.8 1147. 981. 336. 105. 25.2 29.4 13.8
#> 9 31 17.7 1.51 26.7 1048. 860. 234. 68.8 25.5 31.0 12.6
#> 10 35 14.2 1.68 23.8 973. 794. 257. 79.3 24.5 30.0 11.7
#> # ℹ 744 more rows
#> # ℹ 108 more variables: R <dbl>, FeO2 <dbl>, FeCO2 <dbl>, HR <dbl>,
#> # `VO2/HR` <dbl>, Load1 <dbl>, Load2 <dbl>, Load3 <dbl>, Phase <dbl>,
#> # Marker <lgl>, FetO2 <dbl>, FetCO2 <dbl>, FiO2 <dbl>, FiCO2 <dbl>, Ti <dbl>,
#> # Te <dbl>, Ttot <dbl>, `Ti/Ttot` <dbl>, IV <dbl>, PetO2 <dbl>, PetCO2 <dbl>,
#> # `P(a-et)CO2` <dbl>, SpO2 <dbl>, `VD(phys)` <dbl>, `VD/VT` <dbl>,
#> # `Env. Temp.` <dbl>, `Analyz. Temp.` <dbl>, `Analyz. Press.` <dbl>, …
Interpolate
df %>%
interpolate()
#> # Metabolic cart: COSMED
#> # Data status: interpolated data
#> # Time column: t
#> # A tibble: 2,159 × 114
#> t Rf VT VE VO2 VCO2 O2exp CO2exp `VE/VO2` `VE/VCO2` `VO2/Kg`
#> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
#> 1 2 8.08 1.19 9.60 380. 301. 185. 52.9 25.3 31.9 4.58
#> 2 3 15.6 1.05 15.4 622. 483. 163. 46.8 24.9 31.9 7.50
#> 3 4 23.2 0.915 21.2 864. 665. 141. 40.8 24.5 31.9 10.4
#> 4 5 21.3 1.21 24.1 978. 767. 187. 54.9 24.6 31.6 11.8
#> 5 6 19.4 1.51 27.1 1091. 870. 233. 69.0 24.8 31.3 13.1
#> 6 7 17.5 1.81 30.0 1204. 973. 279. 83.1 24.9 30.9 14.5
#> 7 8 15.6 2.11 32.9 1317. 1075. 325. 97.2 25.0 30.6 15.9
#> 8 9 17.3 1.80 30.1 1176. 955. 279. 81.2 25.7 31.8 14.2
#> 9 10 19.0 1.49 27.2 1035. 834. 233. 65.2 26.5 33.0 12.5
#> 10 11 20.6 1.18 24.4 894. 714. 188. 49.2 27.3 34.1 10.8
#> # ℹ 2,149 more rows
#> # ℹ 103 more variables: R <dbl>, FeO2 <dbl>, FeCO2 <dbl>, HR <dbl>,
#> # `VO2/HR` <dbl>, Load1 <dbl>, Load2 <dbl>, Load3 <dbl>, Phase <dbl>,
#> # FetO2 <dbl>, FetCO2 <dbl>, FiO2 <dbl>, FiCO2 <dbl>, Ti <dbl>, Te <dbl>,
#> # Ttot <dbl>, `Ti/Ttot` <dbl>, IV <dbl>, PetO2 <dbl>, PetCO2 <dbl>,
#> # `P(a-et)CO2` <dbl>, SpO2 <dbl>, `VD(phys)` <dbl>, `VD/VT` <dbl>,
#> # `Env. Temp.` <dbl>, `Analyz. Temp.` <dbl>, `Analyz. Press.` <dbl>, …
Perform averages
Bin-average
## example of performing 30-s bin-averages
df %>%
interpolate() %>%
perform_average(type = "bin", bins = 30)
#> # Metabolic cart: COSMED
#> # Data status: averaged data - 30-s bins
#> # Time column: t
#> # A tibble: 72 × 114
#> t Rf VT VE VO2 VCO2 O2exp CO2exp `VE/VO2` `VE/VCO2` `VO2/Kg`
#> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
#> 1 30 16.3 1.75 26.5 1032. 852. 272. 80.5 25.7 31.4 12.4
#> 2 60 19.0 1.39 25.1 1046. 822. 211. 65.0 24.1 30.7 12.6
#> 3 90 16.6 1.76 28.1 1164. 949. 268. 85.0 24.3 29.7 14.0
#> 4 120 17.8 1.93 25.7 1054. 853. 296. 92.5 24.6 30.5 12.7
#> 5 150 15.4 1.68 24.6 993. 823. 257. 80.4 24.8 29.9 12.0
#> 6 180 18.1 1.38 25.1 1058. 833. 209. 65.4 24.0 30.4 12.7
#> 7 210 22.3 1.37 29.1 1122. 935. 213. 63.4 26.0 31.3 13.5
#> 8 240 16.6 1.91 24.9 966. 825. 301. 89.5 25.8 30.2 11.6
#> 9 270 16.8 1.64 26.2 1044. 896. 252. 79.7 25.2 29.4 12.6
#> 10 300 14.5 2.09 27.2 1097. 945. 322. 103. 24.6 28.8 13.2
#> # ℹ 62 more rows
#> # ℹ 103 more variables: R <dbl>, FeO2 <dbl>, FeCO2 <dbl>, HR <dbl>,
#> # `VO2/HR` <dbl>, Load1 <dbl>, Load2 <dbl>, Load3 <dbl>, Phase <dbl>,
#> # FetO2 <dbl>, FetCO2 <dbl>, FiO2 <dbl>, FiCO2 <dbl>, Ti <dbl>, Te <dbl>,
#> # Ttot <dbl>, `Ti/Ttot` <dbl>, IV <dbl>, PetO2 <dbl>, PetCO2 <dbl>,
#> # `P(a-et)CO2` <dbl>, SpO2 <dbl>, `VD(phys)` <dbl>, `VD/VT` <dbl>,
#> # `Env. Temp.` <dbl>, `Analyz. Temp.` <dbl>, `Analyz. Press.` <dbl>, …
Rolling-average
## example of performing 30-s rolling-averages
df %>%
interpolate() %>%
perform_average(type = "rolling", rolling_window = 30)
#> # Metabolic cart: COSMED
#> # Data status: averaged data - 30-s rolling average
#> # Time column: t
#> # A tibble: 2,130 × 114
#> t Rf VT VE VO2 VCO2 O2exp CO2exp `VE/VO2` `VE/VCO2` `VO2/Kg`
#> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
#> 1 16.5 16.4 1.75 26.5 1033. 852. 271. 80.1 25.7 31.3 12.4
#> 2 17.5 16.6 1.76 27.0 1054. 870. 273. 80.7 25.7 31.3 12.7
#> 3 18.5 16.7 1.78 27.3 1067. 882. 276. 81.6 25.7 31.3 12.9
#> 4 19.5 16.4 1.80 27.4 1071. 887. 280. 82.8 25.7 31.2 12.9
#> 5 20.5 16.2 1.82 27.4 1071. 888. 282. 83.6 25.7 31.1 12.9
#> 6 21.5 16.0 1.82 27.3 1068. 885. 282. 83.8 25.7 31.1 12.9
#> 7 22.5 16.0 1.81 27.1 1062. 880. 280. 83.4 25.7 31.1 12.8
#> 8 23.5 16.0 1.78 26.9 1052. 871. 277. 82.4 25.6 31.0 12.7
#> 9 24.5 16.1 1.77 26.7 1048. 867. 274. 81.8 25.5 31.0 12.6
#> 10 25.5 16.1 1.76 26.6 1050. 868. 273. 81.9 25.4 30.8 12.6
#> # ℹ 2,120 more rows
#> # ℹ 103 more variables: R <dbl>, FeO2 <dbl>, FeCO2 <dbl>, HR <dbl>,
#> # `VO2/HR` <dbl>, Load1 <dbl>, Load2 <dbl>, Load3 <dbl>, Phase <dbl>,
#> # FetO2 <dbl>, FetCO2 <dbl>, FiO2 <dbl>, FiCO2 <dbl>, Ti <dbl>, Te <dbl>,
#> # Ttot <dbl>, `Ti/Ttot` <dbl>, IV <dbl>, PetO2 <dbl>, PetCO2 <dbl>,
#> # `P(a-et)CO2` <dbl>, SpO2 <dbl>, `VD(phys)` <dbl>, `VD/VT` <dbl>,
#> # `Env. Temp.` <dbl>, `Analyz. Temp.` <dbl>, `Analyz. Press.` <dbl>, …
Perform VO2 kinetics analysis
results_kinetics <- vo2_kinetics(
.data = df,
intensity_domain = "moderate",
vo2_column = "VO2",
protocol_n_transitions = 3,
protocol_baseline_length = 360,
protocol_transition_length = 360,
cleaning_level = 0.95,
cleaning_baseline_fit = c("linear", "exponential", "exponential"),
fit_level = 0.95,
fit_bin_average = 5,
fit_phase_1_length = 20,
fit_baseline_length = 120,
fit_transition_length = 240,
verbose = TRUE
)
#> ────────────────────────── * V̇O₂ kinetics analysis * ─────────────────────────
#> ✔ Detecting outliers
#> • 14 outliers found in transition 1
#> • 15 outliers found in transition 2
#> • 13 outliers found in transition 3
#> ✔ Processing data...
#> ✔ └─ Removing outliers
#> ✔ └─ Interpolating each transition
#> ✔ └─ Ensemble-averaging transitions
#> ✔ └─ Performing 5-s bin averages
#> ✔ Fitting data...
#> ✔ └─ Fitting baseline
#> ✔ └─ Fitting transition
#> ✔ └─ Calculating residuals
#> ✔ └─ Preparing plots
#> ────────────────────────────────── * DONE * ──────────────────────────────────
Perform VO2max analysis
df_incremental <- read_data(path = system.file("ramp_cosmed.xlsx", package = "whippr"), metabolic_cart = "cosmed")
vo2_max(
.data = df_incremental, ## data from `read_data()`
vo2_column = "VO2",
vo2_relative_column = "VO2/Kg",
heart_rate_column = "HR",
rer_column = "R",
detect_outliers = TRUE,
average_method = "bin",
average_length = 30,
plot = TRUE,
verbose = TRUE,
## arguments for `incremental_normalize()`
incremental_type = "ramp",
has_baseline = TRUE,
baseline_length = 240, ## 4-min baseline
work_rate_magic = TRUE, ## produce a work rate column
baseline_intensity = 20, ## baseline was performed at 20 W
ramp_increase = 25, ## 25 W/min ramp
## arguments for `detect_outliers()`
test_type = "incremental",
cleaning_level = 0.95,
method_incremental = "linear"
)
#> ──────────────────────────── * V̇O₂ max analysis * ────────────────────────────
#> ✔ Normalizing incremental data...
#> ✔ Detecting outliers
#> • 2 outlier(s) found in baseline
#> • 15 outlier(s) found in ramp
#> ✔ Filtering out outliers...
#> ✔ Interpolating from breath-by-breath into second-by-second...
#> ✔ Performing averages...
#> # A tibble: 1 × 6
#> VO2max_absolute VO2max_relative POpeak HRmax RERmax plot
#> <dbl> <dbl> <int> <dbl> <dbl> <list>
#> 1 3514. 45.8 303 193 1.13 <gg>
Metabolic carts currently supported
- COSMED
- CORTEX
- NSpire
- Parvo Medics
- Geratherm Respiratory
- CardioCoach
Online app
Would you like to perform VO2 kinetics analyses but don’t know R? No problem! You can use our online app: VO2 Kinetics App
Code of Conduct
Please note that this project is released with a Contributor Code of Conduct. By participating in this project you agree to abide by its terms.
Icons made by monkik from www.flaticon.com