Weight-Induced Consumed Endurance (WICE): A Model to Quantify Shoulder Fatigue with Weighted Objects

Supplementary Material

Author

Tinghui Li, Eduardo Velloso, Anusha Withana, Zhanna Sarsenbayeva

Published

July 14, 2025

1 Introduction

This code contains the process, models, figures, and results that were used to build and analyze the WICE model. Section 3 details the implementation of the WICE model along with the model summary. Section 4 analyzes the estimated maximum endurance time (ET) from each model using leave-one-out cross validation and Pearson correlation to compare the performance of different models, with posterior prediction plots provided as visual evidence. Section 5 examines the estimated consumed endurance (CE) at 60 seconds using Pearson correlation, and includes posterior prediction plots to further validate the model performance. Section 6 demonstrates the application of the WICE model to compare endurance differences between using hands-only versus controllers, as well as other devices (e.g., haptic devices), as discussed in the paper Discussion section. It also presents the application of the WICE model to investigate the effects of weight and location on endurance time.

2 Library

The key libraries used for model generation and plotting, along with their respective versions, are listed below.

cat("tidyverse:", as.character(packageVersion("tidyverse")), 
    "dplyr:", as.character(packageVersion("dplyr")), 
    "brms:", as.character(packageVersion("brms")), 
    "mgcv:", as.character(packageVersion("mgcv")), 
    "loo:", as.character(packageVersion("loo")), 
    "ggplot2:", as.character(packageVersion("ggplot2")))
tidyverse: 2.0.0 dplyr: 1.1.4 brms: 2.22.0 mgcv: 1.9.1 loo: 2.8.0 ggplot2: 3.5.1

3 WICE Implementation

This section presents the implementation of WICE model and the corresponding model summary. The WICE model includes both the new calculation of T_shoulder and the individual arm mass information.

formula <- bf(
  ET ~ a / (((((T_shoulder_CoM + C_theta) / T_max_NICER) * 100)^b) * c),
  a ~ 1,
  b ~ 1 + (1 | participant),
  c ~ 1,
  nl = TRUE 
)

priors <- c(
  prior(normal(14.86, 10), nlpar = "a", lb = 0),
  prior(normal(1.83, 2), nlpar = "b", lb = 0),
  prior(normal(0.000218, 0.1), nlpar = "c", lb = 0)
)

ET_WICE <- brm(
  formula,
  data = data,
  family = shifted_lognormal(),
  prior = priors,
  iter = 4000, 
  warmup = 2000,
  save_pars = save_pars(all = TRUE)
)

saveRDS(ET_WICE, file = "brm_models/ET_WICE.rds")
ET_WICE <- readRDS("brm_models/ET_WICE.rds")
summary(ET_WICE)
 Family: shifted_lognormal 
  Links: mu = identity; sigma = identity; ndt = identity 
Formula: ET ~ a/(((((T_shoulder_BodyM + C_theta)/T_max_NICER) * 100)^b) * c) 
         a ~ 1
         b ~ 1 + (1 | participant)
         c ~ 1
   Data: data (Number of observations: 190) 
  Draws: 4 chains, each with iter = 6000; warmup = 2000; thin = 1;
         total post-warmup draws = 16000

Multilevel Hyperparameters:
~participant (Number of levels: 38) 
                Estimate Est.Error l-95% CI u-95% CI Rhat Bulk_ESS Tail_ESS
sd(b_Intercept)     0.04      0.01     0.03     0.05 1.00     1981     3180

Regression Coefficients:
            Estimate Est.Error l-95% CI u-95% CI Rhat Bulk_ESS Tail_ESS
a_Intercept     2.18      1.15     0.38     4.75 1.00     5076     3848
b_Intercept     0.39      0.03     0.33     0.45 1.00     4552     7444
c_Intercept     0.13      0.07     0.02     0.29 1.00     5336     3834

Further Distributional Parameters:
      Estimate Est.Error l-95% CI u-95% CI Rhat Bulk_ESS Tail_ESS
sigma     0.32      0.02     0.28     0.36 1.00     7354    10182
ndt       5.35      3.19     0.34    11.85 1.00     6116     5268

Draws were sampled using sampling(NUTS). For each parameter, Bulk_ESS
and Tail_ESS are effective sample size measures, and Rhat is the potential
scale reduction factor on split chains (at convergence, Rhat = 1).

4 Maximum Endurance Time (ET) Analysis

This section contains the estimated maximum endurance time (ET) from each model (CE, NICE, NICER, WICE) using leave-one-out cross validation and Pearson correlation to compare the performance of different models, with posterior prediction plots provided as visual evidence.

This section presents the calculation of Pearson correlation for the posterior predictions of maximum endurance time.

epred_WICE <- posterior_predict(ET_WICE, newdata = data)
data <- data %>% mutate(ET_WICE_pred = colMeans(epred_WICE))

calc_cor_stats <- function(pred_matrix, y_true) {
  cor_draws <- apply(pred_matrix, 1, function(pred_row) {
    cor(pred_row, y_true, method = "pearson")
  })
  tibble(
    cor_median = median(cor_draws),
    cor_lower = quantile(cor_draws, 0.025),
    cor_upper = quantile(cor_draws, 0.975)
  )
}

pred_cols <- c("ET_CE", "ET_NICE", "ET_NICER", "ET_WICE_pred")

This section presents the visualisation of mean posterior predictions.

ET_mean

5 Consumed Endurance (CE) at 60s

This section contains the estimated consumed endurance (CE) at 60 seconds using Pearson correlation, and includes posterior prediction plots to further validate the model performance.

data$WICE_pred <- 100 * (60 / data$ET_WICE_pred)

pred_cols <- c("CE", "NICE", "NICER", "WICE_pred")
data$WICE_pred <- 100 * (60 / data$ET_WICE_pred)

pred_cols <- c("CE", "NICE", "NICER", "WICE_pred")

This section presents the visualisation of mean posterior predictions.

CE_mean

6 WICE Application

This section contains the application of the WICE model to compare endurance differences between using hands-only versus controllers, as well as other devices (e.g., haptic devices), as discussed in the paper Discussion section. It also presents the application of the WICE model to investigate the effects of weight and location on endurance time.

predictions <- predict(ET_WICE, newdata = newdata, allow_new_levels = TRUE)

newdata$Estimate <- round(predictions[, 1], 0)
newdata$Est.Error <- round(predictions[, 2], 0)
newdata$Q2.5 <- round(predictions[, 3], 0)
newdata$Q97.5 <- round(predictions[, 4], 0)

grouped_means <- newdata %>%
  group_by(product, M_object, gender) %>%
  summarise(Estimate = round(mean(Estimate, na.rm = TRUE), 0),
            Error = round(mean(Est.Error, na.rm = TRUE), 0),
            Q2.5 = round(mean(Q2.5, na.rm = TRUE), 0),
            Q97.5 = round(mean(Q97.5, na.rm = TRUE), 0),
            .groups = "drop")

print(as.data.frame(grouped_means))
            product M_object gender Estimate Error Q2.5 Q97.5
1  Apple Vision Pro    0.000 Female      227    80  111   419
2  Apple Vision Pro    0.000   Male      281    99  137   519
3        Cybergrasp    0.450 Female      189    66   93   347
4        Cybergrasp    0.450   Male      244    85  119   448
5             Dexmo    0.300 Female      200    70   98   368
6             Dexmo    0.300   Male      255    89  124   470
7             ELAXO    0.540 Female      183    63   90   335
8             ELAXO    0.540   Male      237    83  116   436
9         HandMorph    0.171 Female      211    74  103   388
10        HandMorph    0.171   Male      265    93  129   489
11       HapThimble    0.100 Female      218    77  106   401
12       HapThimble    0.100   Male      272    96  132   502
13     Haptic Glove    0.640 Female      176    61   87   323
14     Haptic Glove    0.640   Male      230    80  113   423
15 HTC Vive Focus 3    0.142 Female      214    75  104   394
16 HTC Vive Focus 3    0.142   Male      268    94  130   494
17     Meta Quest 3    0.126 Female      215    75  105   396
18     Meta Quest 3    0.126   Male      270    95  131   497
19    Meta Quest 3S    0.103 Female      218    76  106   401
20    Meta Quest 3S    0.103   Male      271    95  132   500
21   Meta Quest Pro    0.164 Female      212    74  104   390
22   Meta Quest Pro    0.164   Male      266    94  130   491
23           Pico 4    0.184 Female      210    74  103   386
24           Pico 4    0.184   Male      265    93  129   487
25   PlayStation VR    0.162 Female      212    74  104   390
26   PlayStation VR    0.162   Male      266    94  130   491
gender

location

weight