Fitting hierarchical pupil time-course models
Source:vignettes/fitting-pupil-timecourse-models.Rmd
fitting-pupil-timecourse-models.RmdApproved family
The first direct pupil model family is Gaussian with an identity link. It supports a governed temporal trajectory, optional condition-specific trajectory, participant hierarchy, optional item hierarchy, declared numeric nuisance covariates, and optional AR(1) dependence for sufficiently regular within-trial sampling.
sim <- simulate_pupil_timecourse(
n_participants = 5,
trials_per_participant = 4,
sampling_frequency = 20,
time_window = c(-0.4, 1.2),
baseline_window = c(-0.4, 0),
blink_trial_probability = 0,
seed = 2026
)
contract <- create_pupil_contract(
outcome_col = "pupil_mm",
participant_col = "participant_id",
trial_col = "trial_id",
item_col = "item_id",
condition_col = "condition",
time_col = "event_time",
pupil_unit = "millimetres",
sampling_frequency = 20,
eye = "combined"
)
prepared <- prepare_pupil_timecourse(sim$data, contract)
spec <- specify_pupil_timecourse_model(
prepared,
temporal_structure = "smooth",
smooth_basis_dimension = 5,
condition_trajectory = TRUE,
autocorrelation = "none"
)
spec
#> <gp3bayes_pupil_model_specification>
#> Family: Gaussian pupil time-course
#> Formula: .pupil_model ~ .condition + s(.event_time, by = .condition, k = 5) + (1 | .participant) + (1 | .item)
#> Temporal structure: smooth
#> Condition trajectory: TRUE
#> Autocorrelation: none
#> Outcome unit: millimetres
#> Baseline: none
#> Unrestricted formula: FALSE
#> Fit performed: FALSETranslation without fitting
translation <- translate_pupil_model_to_brms(spec)
translation$formula
translation$priorTranslation is restricted. The user does not provide an arbitrary formula, family, Stan program, algorithm, or open-ended backend argument list.
Prior-predictive gate
Prior-predictive execution is governed separately from posterior fitting. The default call records the approved prior-only plan and does not compile Stan.
prior_plan <- check_pupil_prior_predictive(
spec,
execute = FALSE,
draws = 100,
chains = 2,
iter = 200,
warmup = 100
)
as.data.frame(prior_plan)
#> field value
#> 1 family Gaussian
#> 2 backend rstan
#> 3 draws 100
#> 4 chains 2
#> 5 iter 200
#> 6 warmup 100
#> 7 cores 2
#> 8 outcome_unit millimetres
#> 9 execute FALSEA researcher can set execute = TRUE with either approved
backend during manual analysis. The operation never changes priors
automatically and its evidence does not certify model adequacy.
Full-MCMC backends
Real fitting is optional and requires brms plus one
approved backend.
fit_rstan <- fit_pupil_model_backend(
spec,
backend = "rstan",
chains = 2,
iter = 1000,
warmup = 500,
cores = 2,
seed = 20260814
)
fit_cmdstanr <- fit_pupil_model_backend(
spec,
backend = "cmdstanr",
chains = 2,
iter = 1000,
warmup = 500,
cores = 2,
seed = 20260814
)The wrappers preserve a common gp3bayes object shape. A fitted object does not by itself establish convergence, adequacy, measurement validity, or a causal interpretation.