Exposure to false cardiac feedback alters pain perception and anticipatory cardiac frequency.
Paper
Loaded from Europe PMC by your browser, not stored by OSCR: doi.org · Europe PMC
The paper is loaded when this pane is shown.
The authors' code
R · 947 lines · 36 KB · MIT
- # Clear variables
- rm(list = ls())
- library(readxl)
- library(lme4)
- library(optimx)
- library(lmerTest)
- library(effects)
- library(emmeans) #
- library(brms)
- # load data
- setwd("C:/Users/Eleonora/OneDrive/MyExperiments/Interoception_exp/2_pain perception/")
- data <- read_excel("Data_v3 - 2504.xlsx")
- # recode factors
- data$Exp <- factor(data$Exp, levels = c("Intero", "Extero"))
- data$Feedback <- factor(data$Feedback, levels = c("Congruent", "Slower", "Faster", "No Feedback"))
- # remove stim int levels
- data = data[data$StimInt != "5", ]
- data = data[data$StimInt != "1", ]
- # Center Stim intensity (2 = -.5; 3 = 0; 4 = .5)
- data$StimInt <- (data$StimInt-3)/2
- #################
- ### LMM Btw ####
- #################
- ################### HR BETWEEN ###################
- MBtw.HR_N0 = lmer(HR ~ Exp*Feedback*Trial + (1|SSID),data = data, REML = TRUE,
- control = lmerControl(optimizer = "optimx", calc.derivs = FALSE,
- optCtrl = list(method = "nlminb", starttests = FALSE, kkt = FALSE)))
- MBtw.HR_N = lmer(HR ~ Exp*Feedback*Trial + (Trial|SSID),data = data, REML = TRUE,
- control = lmerControl(optimizer = "optimx", calc.derivs = FALSE,
- optCtrl = list(method = "nlminb", starttests = FALSE, kkt = FALSE)))
- model_comparison <- anova(MBtw.HR_N0, MBtw.HR_N)
- model_comparison
- MBtw.HR_N = lmer(HR ~ Exp*Feedback*Trial + (Trial|SSID),data = data, REML = TRUE,
- control = lmerControl(optimizer = "optimx", calc.derivs = FALSE,
- optCtrl = list(method = "nlminb", starttests = FALSE, kkt = FALSE)))
- # remove outliers (|standardized residuals| > 2 SDs)
- MBtw.HRt_N = lmer(HR ~ Exp*Feedback*Trial + (Trial|SSID),data = data,REML = TRUE,
- subset = abs(scale(resid(MBtw.HR_N)))<2,
- control = lmerControl(optimizer = "optimx", calc.derivs = FALSE,
- optCtrl = list(method = "nlminb", starttests = FALSE, kkt = FALSE)))
- # residual analysis
- qqnorm(resid(MBtw.HRt_N))
- qqline(resid(MBtw.HRt_N))
- # show model results
- anova(MBtw.HRt_N)
- summary(MBtw.HRt_N)
- # save model results
- F_Btw.HR_N = anova(MBtw.HRt_N)
- T_Btw.HR_N = data.frame(summary(MBtw.HRt_N)$coefficients)
- posthoc_results <- emmeans(MBtw.HRt_N, pairwise ~ Feedback, adjust="fdr")
- posthoc_results
- # forziamo il download della versione binaria senza compilare
- install.packages("DHARMa", type = "binary", dependencies = TRUE, repos = "https://cran.rstudio.com")
- library(DHARMa)library(DHARMa)
- sim <- simulateResiduals(fittedModel = MBtw.HRt_N, n = 1000)
- plotQQunif(sim)
- testNormality(sim)
- testDispersion(sim)
- ################### HR BETWEEN INTERACTIONS ###################
- ### FEEDBACK * EXP
- library(emmeans)
- emmeans_FE <- emmeans(MBtw.HRt_N, ~ Feedback * Exp)
- summary(emmeans_FE) #summary(emmeans_FE, infer = c(TRUE, TRUE)) # HA SENSO?
- #Contrasti tra feedback entro ciascun esperimento
- contrast(emmeans_FE, method = "pairwise", by = "Exp", adjust = "fdr")
- #Contrasti di interazione (cioè: la differenza delle differenze)
- contrast(emmeans_FE, interaction = "pairwise")
- #Contrasti tra feedback entro ciascun esperimento
- contrast(emmeans_FE, method = "pairwise", by = "Feedback", adjust = "fdr")
- ###FEEDBACK*TRIAL
- library(emmeans)
- # Calcola la slope del Trial nei due livelli di Exp
- emtrends(MBtw.HRt_N, var = "Trial", specs = "Exp")
- emtrends(MBtw.HRt_N, var = "Trial", specs = "Exp", infer = c(TRUE, TRUE), adjust = "none")
- contrast(emtrends(MBtw.HRt_N, var = "Trial", specs = "Exp"), method = "pairwise")
- ## FEEDBACK * TRIAL * EXPERIMENT
- anova(MBtw.HRt_N)
- summary(MBtw.HRt_N)
- library(emmeans)
- # Stima degli slopes per ogni condizione Feedback × Exp
- # Estrai le slope di HR su Trial
- slopes_HR <- emtrends(MBtw.HRt_N, ~ Feedback * Exp, var = "Trial")
- # slope significative (aumento/decremento diverso da zero per ogni cond (exp e feedback))
- summary(slopes_HR, infer = c(TRUE, TRUE)) # per avere anche t, p e CI, usa questo, non contrast(slopes_HR)
- #dentro a ogni esperimento
- contrast(slopes_HR, method = "pairwise", by = "Exp", adjust = "fdr")
- # differenze delle differenze TRA esperimenti
- interaction_contrast <- contrast(slopes_HR, interaction = "pairwise")
- summary(interaction_contrast)
- #Tutti i confronti possibili tra condizioni (es. Congruent Intero vs Faster Extero)
- contrast(slopes_HR, method = "pairwise", adjust = "fdr")
- trial_points <- c(-0.5, 0, 0.5)
- # Estimated marginal means at specific trial values
- em_trial <- emmeans(MBtw.HRt_N, ~ Feedback * Exp | Trial, at = list(Trial = trial_points))
- # View predictions
- summary(em_trial)
- contrast(em_trial, method = "pairwise", by = c("Trial", "Feedback"), adjust = "fdr")
- library(emmeans)
- library(ggplot2)
- # 1. Definisci i tre livelli di interesse per Trial (già centrato)
- trial_levels <- c(-0.5, 0, 0.5)
- # 2. Calcola gli emmeans a ciascun livello di Trial
- em_trial <- emmeans(MBtw.HRt_N, ~ Feedback | Exp * Trial, at = list(Trial = trial_levels))
- # 3. Contrasti tra condizioni di Feedback all’interno di ogni Exp × Trial
- contrasts_by_trial <- contrast(em_trial, method = "pairwise", by = c("Exp", "Trial"), adjust = "fdr")
- # 4. Visualizza i risultati dei contrasti
- summary(contrasts_by_trial)
- # 1. Cambiamento nel tempo (slopes) per ogni Feedback: confronto Intero vs Extero
- slopes_HR <- emtrends(MBtw.HRt_N, ~ Feedback * Exp, var = "Trial")
- # Contrasti di interazione: slope_Intero - slope_Extero per ciascun Feedback
- slope_diff <- contrast(slopes_HR, interaction = "pairwise")
- summary(slope_diff)
- # → Se estimate ≠ 0 e p < .05, significa che quel Feedback cambia con Trial in modo diverso tra Exp
- # 2. Faster vs Slower a Trial = -0.5, 0, 0.5 dentro ciascun Exp
- trial_levels <- c(-0.5, 0, 0.5)
- # Calcola gli emmeans per Feedback in ciascun Exp ai trial prescelti
- em_trial <- emmeans(
- MBtw.HRt_N,
- ~ Feedback | Exp * Trial,
- at = list(Trial = trial_levels)
- )
- # Contrasto custom: Faster vs Slower (vettore su livelli di Feedback: Congruent, Slower, Faster, No Feedback)
- fs_contrasts <- contrast(
- em_trial,
- method = list("Faster vs Slower" = c(0, -1, 1, 0)),
- by = c("Exp", "Trial"),
- adjust = "fdr"
- )
- # Risultati
- summary(fs_contrasts)
- # → Per ogni Exp × Trial ottieni stima, t-ratio e p-value di Faster–Slower
- ################### LIKERT BETWEEEN ################### qui ok feedback
- MBtw.LIK_N0 = lmer(LIK ~ Exp*Feedback*StimInt*Trial + (1|SSID),data = data,
- control = lmerControl(optimizer = "optimx", calc.derivs = FALSE,
- optCtrl = list(method = "nlminb", starttests = FALSE, kkt = FALSE)))
- MBtw.LIK_N = lmer(LIK ~ Exp*Feedback*StimInt*Trial + (StimInt+Trial|SSID),data = data,
- control = lmerControl(optimizer = "optimx", calc.derivs = FALSE,
- optCtrl = list(method = "nlminb", starttests = FALSE, kkt = FALSE)))
- MBtw.LIK_N1 = lmer(LIK ~ Exp*Feedback*StimInt*Trial + (StimInt+Trial+Feedback|SSID),data = data,
- control = lmerControl(optimizer = "optimx", calc.derivs = FALSE,
- optCtrl = list(method = "nlminb", starttests = FALSE, kkt = FALSE)))
- model_comparison <- anova(MBtw.LIK_N, MBtw.LIK_N1)
- model_comparison
- MBtw.LIK_N = lmer(LIK ~ Exp*Feedback*StimInt*Trial + (StimInt+Trial+Feedback|SSID),data = data,
- control = lmerControl(optimizer = "optimx", calc.derivs = FALSE,
- optCtrl = list(method = "nlminb", starttests = FALSE, kkt = FALSE)))
- # remove outliers (|standardized residuals| > 2 SDs)
- MBtw.LIKt_N = lmer(LIK ~ Exp*Feedback*StimInt*Trial + (StimInt+Trial+Feedback|SSID),data = data,
- subset = abs(scale(resid(MBtw.LIK_N)))<2,
- control = lmerControl(optimizer = "optimx", calc.derivs = FALSE,
- optCtrl = list(method = "nlminb", starttests = FALSE, kkt = FALSE)))
- # residual analysis
- qqnorm(resid(MBtw.LIKt_N))
- qqline(resid(MBtw.LIKt_N))
- # show model results
- anova(MBtw.LIKt_N)
- summary(MBtw.LIKt_N)
- # save model results
- F_Btw.LIK_N = anova(MBtw.LIKt_N)
- T_Btw.LIK_N = data.frame(summary(MBtw.LIKt_N)$coefficients)
- posthoc_results <- emmeans(MBtw.LIKt_N, pairwise ~ Feedback, adjust="fdr")
- posthoc_results
- ################### LIKERT BETWEEN INTERACTIONS ###################
- # FEEDBACK * EXP
- library(emmeans)
- emmeans_FE <- emmeans(MBtw.LIKt_N, ~ Feedback * Exp)
- summary(emmeans_FE)
- #Contrasti tra feedback entro ciascun esperimento
- contrast(emmeans_FE, method = "pairwise", by = "Exp", adjust = "fdr")
- #Contrasti di interazione (cioè: la differenza delle differenze)
- contrast(emmeans_FE, interaction = "pairwise")
- # STIMINT*TRIAL
- slopes_stimint_at <- emtrends(MBtw.LIKt_N, ~ StimInt, var = "Trial", at = list(StimInt = c(-0.5, 0, 0.5)))
- summary(slopes_stimint_at)
- test(slopes_stimint_at)
- contrast(slopes_stimint_at, method = "pairwise", adjust = "fdr")
- #FEEDBACK * STIMINT
- em_stimint <- emmeans(MBtw.LIKt_N, ~ Feedback | StimInt, at = list(StimInt = c(-0.5, 0, 0.5)))
- summary(em_stimint, infer = c(TRUE, TRUE))
- # Pairwise comparisons tra livelli di feedback, per ogni StimInt
- contrast(em_stimint, method = "pairwise", adjust = "fdr")
- # 1. Calcola le slope (trend) di StimInt per ciascun livello di Feedback
- slopes_feedback <- emtrends(MBtw.LIKt_N, ~ Feedback, var = "StimInt")
- # 2. Riassunto delle stime: slope, SE, t, p, CI
- summary(slopes_feedback)
- test(slopes_feedback)
- # Contrasti sulle slope di StimInt tra condizioni di feedback
- contrast(slopes_feedback, method = "pairwise", adjust = "fdr")
- ###FEEDBACK*TRIAL
- # Calcolo delle slope dell’effetto di Trial all’interno di ogni livello di Feedback
- slopes_trial_by_feedback <- emtrends(MBtw.LIKt_N, ~ Feedback, var = "Trial")
- summary(slopes_trial_by_feedback, infer = c(TRUE, TRUE)) # per avere anche t, p e CI
- pairs(slopes_trial_by_feedback, adjust = "fdr")
- # Contrasti tra le pendenze di Trial tra i diversi livelli di Feedback
- trial_slope_contrasts <- pairs(slopes_trial_by_feedback, adjust = "fdr")
- summary(trial_slope_contrasts)
- plot(slopes_trial_by_feedback)
- ## what happens at each trial level
- feedback_by_trial_levels <- emmeans(MBtw.LIKt_N, ~ Feedback | Trial,
- at = list(Trial = c(-0.5, 0, 0.5)))
- pairs(feedback_by_trial_levels, adjust = "fdr")
- ################### NPS BETWEEN ###################
- MBtw.VAS_NO = lmer(VAS ~ Exp*Feedback*StimInt*Trial +(1|SSID),data = data,
- control = lmerControl(optimizer = "optimx", calc.derivs = FALSE,
- optCtrl = list(method = "nlminb", starttests = FALSE, kkt = FALSE)))
- MBtw.VAS_N = lmer(VAS ~ Exp*Feedback*StimInt*Trial +(StimInt+Trial|SSID),data = data,
- control = lmerControl(optimizer = "optimx", calc.derivs = FALSE,
- optCtrl = list(method = "nlminb", starttests = FALSE, kkt = FALSE)))
- model_comparison <- anova(MBtw.VAS_NO, MBtw.VAS_N)
- model_comparison
- MBtw.VAS_N = lmer(VAS ~ Exp*Feedback*StimInt*Trial +(StimInt+Trial|SSID),data = data,
- control = lmerControl(optimizer = "optimx", calc.derivs = FALSE,
- optCtrl = list(method = "nlminb", starttests = FALSE, kkt = FALSE)))
- # remove outliers (|standardized residuals| > 2 SDs)
- MBtw.VASt_N = lmer(VAS ~ Exp*Feedback*StimInt*Trial +(StimInt+Trial|SSID),data = data,
- subset = abs(scale(resid(MBtw.VAS_N)))<2,
- control = lmerControl(optimizer = "optimx", calc.derivs = FALSE,
- optCtrl = list(method = "nlminb", starttests = FALSE, kkt = FALSE)))
- # residual analysis
- qqnorm(resid(MBtw.VASt_N))
- qqline(resid(MBtw.VASt_N))
- # show model results
- anova(MBtw.VASt_N)
- summary(MBtw.VASt_N)
- # save model results
- F_Btw.VAS_N = anova(MBtw.VASt_N)
- T_Btw.VAS_N = data.frame(summary(MBtw.VASt_N)$coefficients)
- posthoc_results <- emmeans(MBtw.VASt_N, pairwise ~ Feedback, adjust="fdr")
- posthoc_results
- ################### NPS BETWEEN INTERACTIONS ###################
- # FEEDBACK * EXP
- library(emmeans)
- emmeans_FE <- emmeans(MBtw.VASt_N, ~ Feedback * Exp)
- summary(emmeans_FE)
- #Contrasti tra feedback entro ciascun esperimento
- contrast(emmeans_FE, method = "pairwise", by = "Exp", adjust = "fdr")
- #Contrasti di interazione (cioè: la differenza delle differenze)
- contrast(emmeans_FE, interaction = "pairwise")
- # STIMINT*TRIAL
- slopes_stimint_at <- emtrends(MBtw.VASt_N, ~ StimInt, var = "Trial", at = list(StimInt = c(-0.5, 0, 0.5)))
- summary(slopes_stimint_at)
- test(slopes_stimint_at)
- contrast(slopes_stimint_at, method = "pairwise", adjust = "fdr")
- #FEEDBACK * STIMINT
- em_stimint <- emmeans(MBtw.VASt_N, ~ Feedback | StimInt, at = list(StimInt = c(-0.5, 0, 0.5)))
- summary(em_stimint, infer = c(TRUE, TRUE))
- # Pairwise comparisons tra livelli di feedback, per ogni StimInt
- contrast(em_stimint, method = "pairwise", adjust = "fdr")
- # 1. Calcola le slope (trend) di StimInt per ciascun livello di Feedback
- slopes_feedback <- emtrends(MBtw.VASt_N, ~ Feedback, var = "StimInt")
- # 2. Riassunto delle stime: slope, SE, t, p, CI
- summary(slopes_feedback)
- test(slopes_feedback)
- # Contrasti sulle slope di StimInt tra condizioni di feedback
- contrast(slopes_feedback, method = "pairwise", adjust = "fdr")
- ###FEEDBACK*TRIAL
- # Calcolo delle slope dell’effetto di Trial all’interno di ogni livello di Feedback
- slopes_trial_by_feedback <- emtrends(MBtw.VASt_N, ~ Feedback, var = "Trial")
- summary(slopes_trial_by_feedback, infer = c(TRUE, TRUE)) # per avere anche t, p e CI
- pairs(slopes_trial_by_feedback, adjust = "fdr")
- # Contrasti tra le pendenze di Trial tra i diversi livelli di Feedback
- trial_slope_contrasts <- pairs(slopes_trial_by_feedback, adjust = "fdr")
- summary(trial_slope_contrasts)
- plot(slopes_trial_by_feedback)
- ## what happens at each trial level
- feedback_by_trial_levels <- emmeans(MBtw.VASt_N, ~ Feedback | Trial,
- at = list(Trial = c(-0.5, 0, 0.5)))
- pairs(feedback_by_trial_levels, adjust = "fdr")
- ###################
- ### LMM Intero ####
- ###################
- data1 = data[data$Exp=="Intero", ]
- ################### HR Interoceptive ###################
- MInt.HRN0 = lmer(HR ~ Feedback*Trial + (1|SSID),data = data1, REML = TRUE,
- control = lmerControl(optimizer = "optimx", calc.derivs = FALSE,
- optCtrl = list(method = "nlminb", starttests = FALSE, kkt = FALSE)))
- MInt.HRN = lmer(HR ~ Feedback*Trial + (Trial|SSID),data = data1, REML = TRUE,
- control = lmerControl(optimizer = "optimx", calc.derivs = FALSE,
- optCtrl = list(method = "nlminb", starttests = FALSE, kkt = FALSE)))
- model_comparison <- anova(MInt.HRN0, MInt.HRN)
- model_comparison
- # remove outliers (|standardized residuals| > 2 SDs)
- MInt.HRt = lmer(HR ~ Trial*Feedback + (Trial|SSID),data = data1, REML = TRUE,
- subset = abs(scale(resid(MInt.HRN)))<2,
- control = lmerControl(optimizer = "optimx", calc.derivs = FALSE,
- optCtrl = list(method = "nlminb", starttests = FALSE, kkt = FALSE)))
- # residual analysis
- qqnorm(resid(MInt.HRt))
- qqline(resid(MInt.HRt))
- # show model results
- anova(MInt.HRt)
- summary(MInt.HRt)
- # save model results
- F_Int.HR = anova(MInt.HRt)
- T_Int.HR = data.frame(summary(MInt.HRt)$coefficients)
- posthoc_results <- emmeans(MInt.HRt, pairwise ~ Feedback, adjust="fdr")
- posthoc_results
- ################### HR Interoceptive INTERACTIONS ###################
- ## FEEDBACK * TRIAL
- # Calcolo delle slope dell’effetto di Trial all’interno di ogni livello di Feedback
- slopes_trial_by_feedback <- emtrends(MInt.HRt, ~ Feedback, var = "Trial")
- summary(slopes_trial_by_feedback, infer = c(TRUE, TRUE)) # per avere anche t, p e CI
- pairs(slopes_trial_by_feedback, adjust = "fdr")
- # Contrasti tra le pendenze di Trial tra i diversi livelli di Feedback
- trial_slope_contrasts <- pairs(slopes_trial_by_feedback, adjust = "fdr")
- summary(trial_slope_contrasts)
- plot(slopes_trial_by_feedback)
- ## what happens at each trial level
- feedback_by_trial_levels <- emmeans(MInt.HRt, ~ Feedback | Trial,
- at = list(Trial = c(-0.5, 0, 0.5)))
- feedback_by_trial_levels
- pairs(feedback_by_trial_levels, adjust = "fdr")
- ################### LIKERT Interoceptive ################### qui ok feedback
- MInt.LIK1 = lmer(LIK ~ Trial*Feedback*StimInt + (1|SSID),data = data1, REML = TRUE,
- control = lmerControl(optimizer = "optimx", calc.derivs = FALSE,
- optCtrl = list(method = "nlminb", starttests = FALSE, kkt = FALSE)))
- MInt.LIK = lmer(LIK ~ Trial*Feedback*StimInt + (StimInt+Trial|SSID),data = data1, REML = TRUE,
- control = lmerControl(optimizer = "optimx", calc.derivs = FALSE,
- optCtrl = list(method = "nlminb", starttests = FALSE, kkt = FALSE)))
- model_comparison <- anova(MInt.LIK1, MInt.LIK)
- model_comparison
- # remove outliers (|standardized residuals| > 2 SDs)
- MInt.LIKt = lmer(LIK ~ Trial*Feedback*StimInt + (StimInt+Trial|SSID),data = data1, REML = TRUE,
- subset = abs(scale(resid(MInt.LIK)))<2,
- control = lmerControl(optimizer = "optimx", calc.derivs = FALSE,
- optCtrl = list(method = "nlminb", starttests = FALSE, kkt = FALSE)))
- # residual analysis
- qqnorm(resid(MInt.LIKt))
- qqline(resid(MInt.LIKt))
- # show model results
- anova(MInt.LIKt)
- summary(MInt.LIKt)
- # save model results
- F_Int.LIK = anova(MInt.LIKt)
- T_Int.LIK = data.frame(summary(MInt.LIKt)$coefficients)
- posthoc_results <- emmeans(MInt.LIKt, pairwise ~ Feedback, adjust="fdr")
- posthoc_results
- ################### LIKERT Interoceptive INTERACTIONS ###################
- #FEEDBACK * STIMINT
- em_stimint <- emmeans(MInt.LIKt, ~ Feedback | StimInt, at = list(StimInt = c(-0.5, 0, 0.5)))
- summary(em_stimint, infer = c(TRUE, TRUE))
- # Pairwise comparisons tra livelli di feedback, per ogni StimInt
- contrast(em_stimint, method = "pairwise", adjust = "fdr")
- # 1. Calcola le slope (trend) di StimInt per ciascun livello di Feedback
- slopes_feedback <- emtrends(MInt.LIKt, ~ Feedback, var = "StimInt")
- # 2. Riassunto delle stime: slope, SE, t, p, CI
- summary(slopes_feedback)
- test(slopes_feedback)
- # Contrasti sulle slope di StimInt tra condizioni di feedback
- contrast(slopes_feedback, method = "pairwise", adjust = "fdr")
- ## FEEDBACK*TRIAL
- # Calcolo delle slope dell’effetto di Trial all’interno di ogni livello di Feedback
- slopes_trial_by_feedback <- emtrends(MInt.LIKt, ~ Feedback, var = "Trial")
- summary(slopes_trial_by_feedback, infer = c(TRUE, TRUE)) # per avere anche t, p e CI
- pairs(slopes_trial_by_feedback, adjust = "fdr")
- # Contrasti tra le pendenze di Trial tra i diversi livelli di Feedback
- trial_slope_contrasts <- pairs(slopes_trial_by_feedback, adjust = "fdr")
- summary(trial_slope_contrasts)
- #plot(slopes_trial_by_feedback)
- ## what happens at each trial level
- feedback_by_trial_levels <- emmeans(MInt.LIKt, ~ Feedback | Trial,
- at = list(Trial = c(-0.5, 0, 0.5)))
- pairs(feedback_by_trial_levels, adjust = "fdr")
- # STIMINT * TRIAL
- slopes_stimint_at <- emtrends(MInt.LIKt, ~ StimInt, var = "Trial", at = list(StimInt = c(-0.5, 0, 0.5)))
- summary(slopes_stimint_at, infer = c(TRUE, TRUE)) # p values diverso da zero?
- #differenze delle differenze
- contrast(slopes_stimint_at, method = "pairwise", adjust = "fdr")
- ################### NPS Interoceptive ###################
- MInt.VAS1 = lmer(VAS ~ Trial*Feedback*StimInt + (1|SSID),data = data1, REML = TRUE,
- control = lmerControl(optimizer = "optimx", calc.derivs = FALSE,
- optCtrl = list(method = "nlminb", starttests = FALSE, kkt = FALSE)))
- MInt.VAS = lmer(VAS ~ Trial*Feedback*StimInt + (StimInt+Trial|SSID),data = data1, REML = TRUE,
- control = lmerControl(optimizer = "optimx", calc.derivs = FALSE,
- optCtrl = list(method = "nlminb", starttests = FALSE, kkt = FALSE)))
- model_comparison <- anova(MInt.VAS1, MInt.VAS)
- model_comparison
- # remove outliers (|standardized residuals| > 2 SDs)
- MInt.VASt = lmer(VAS ~ Trial*Feedback*StimInt + (StimInt+Trial|SSID),data = data1, REML = TRUE,
- subset = abs(scale(resid(MInt.VAS)))<2,
- control = lmerControl(optimizer = "optimx", calc.derivs = FALSE,
- optCtrl = list(method = "nlminb", starttests = FALSE, kkt = FALSE)))
- # residual analysis
- qqnorm(resid(MInt.VASt))
- qqline(resid(MInt.VASt))
- # show model results
- anova(MInt.VASt)
- summary(MInt.VASt)
- # save model results
- F_Int.VAS = anova(MInt.VASt)
- T_Int.VAS = data.frame(summary(MInt.VASt)$coefficients)
- posthoc_results <- emmeans(MInt.VASt, pairwise ~ Feedback, adjust="fdr")
- posthoc_results
- ################### NPS Interoceptive INTERACTIONS ###################
- # FEEDBACK*STIMINT
- # Estimated marginal means di VAS per ciascun livello di Feedback, ai tre livelli di StimInt
- em_stimint <- emmeans(MInt.VASt, ~ Feedback | StimInt, at = list(StimInt = c(-0.5, 0, 0.5)))
- summary(em_stimint, infer = c(TRUE, TRUE))
- # Pairwise comparisons dentro a ogni StimInt
- contrast(em_stimint, method = "pairwise", by = "StimInt", adjust = "fdr")
- slopes_feedback <- emtrends(MInt.VASt, ~ Feedback, var = "StimInt")
- # 2. Riassunto delle stime: slope, SE, t, p, CI
- summary(slopes_feedback, infer = c(TRUE, TRUE))
- # Contrasti sulle slope di StimInt tra condizioni di feedback
- contrast(slopes_feedback, method = "pairwise", adjust = "fdr")
- ###FEEDBACK * TRIAL
- # Calcolo delle slope dell’effetto di Trial all’interno di ogni livello di Feedback
- slopes_trial_by_feedback <- emtrends(MInt.VASt, ~ Feedback, var = "Trial")
- summary(slopes_trial_by_feedback, infer = c(TRUE, TRUE)) # per avere anche t, p e CI
- pairs(slopes_trial_by_feedback, adjust = "fdr")
- # Contrasti tra le pendenze di Trial tra i diversi livelli di Feedback
- trial_slope_contrasts <- pairs(slopes_trial_by_feedback, adjust = "fdr")
- summary(trial_slope_contrasts)
- #plot(slopes_trial_by_feedback)
- ## what happens at each trial level
- feedback_by_trial_levels <- emmeans(MInt.VASt, ~ Feedback | Trial,
- at = list(Trial = c(-0.5, 0, 0.5)))
- pairs(feedback_by_trial_levels, adjust = "fdr")
- ###################
- ### LMM Extero ####
- ###################
- data2 = data[data$Exp=="Extero", ]
- ################### HR exteroceptive ###################
- MExt.HR0 = lmer(HR ~ Trial+Feedback + (1|SSID),data = data2, REML = TRUE,
- control = lmerControl(optimizer = "optimx", calc.derivs = FALSE,
- optCtrl = list(method = "nlminb", starttests = FALSE, kkt = FALSE)))
- MExt.HR = lmer(HR ~ Trial*Feedback + (Trial|SSID),data = data2, REML = TRUE,
- control = lmerControl(optimizer = "optimx", calc.derivs = FALSE,
- optCtrl = list(method = "nlminb", starttests = FALSE, kkt = FALSE)))
- model_comparison <- anova(MExt.HR0, MExt.HR)
- model_comparison
- # remove outliers (|standardized residuals| > 2 SDs)
- MExt.HRt = lmer(HR ~ Trial*Feedback + (Trial|SSID),data = data2, REML = TRUE,
- subset = abs(scale(resid(MExt.HR)))<2,
- control = lmerControl(optimizer = "optimx", calc.derivs = FALSE,
- optCtrl = list(method = "nlminb", starttests = FALSE, kkt = FALSE)))
- # residual analysis
- qqnorm(resid(MExt.HRt))
- qqline(resid(MExt.HRt))
- # show model results
- anova(MExt.HRt)
- summary(MExt.HRt)
- # save model results
- F_Ext.HR = anova(MExt.HRt)
- T_Ext.HR = data.frame(summary(MExt.HRt)$coefficients)
- posthoc_results <- emmeans(MExt.HRt, pairwise ~ Feedback, adjust="fdr")
- posthoc_results
- ################### likert exteroceptive ###################
- MExt.LIK0 = lmer(LIK ~ Trial*Feedback*StimInt + (1|SSID),data = data2, REML = TRUE,
- control = lmerControl(optimizer = "optimx", calc.derivs = FALSE,
- optCtrl = list(method = "nlminb", starttests = FALSE, kkt = FALSE)))
- MExt.LIK = lmer(LIK ~ Trial*Feedback*StimInt + (StimInt+Trial|SSID),data = data2, REML = TRUE,
- control = lmerControl(optimizer = "optimx", calc.derivs = FALSE,
- optCtrl = list(method = "nlminb", starttests = FALSE, kkt = FALSE)))
- model_comparison <- anova(MExt.LIK0, MExt.LIK)
- model_comparison
- # remove outliers (|standardized residuals| > 2 SDs)
- MExt.LIKt = lmer(LIK ~ Trial*Feedback*StimInt + (StimInt+Trial|SSID),data = data2, REML = TRUE,
- subset = abs(scale(resid(MExt.LIK)))<2,
- control = lmerControl(optimizer = "optimx", calc.derivs = FALSE,
- optCtrl = list(method = "nlminb", starttests = FALSE, kkt = FALSE)))
- # residual analysis
- qqnorm(resid(MExt.LIKt))
- qqline(resid(MExt.LIKt))
- # show model results
- anova(MExt.LIKt)
- summary(MExt.LIKt)
- # save model results
- F_Ext.LIK = anova(MExt.LIKt)
- T_Ext.LIK = data.frame(summary(MExt.LIKt)$coefficients)
- posthoc_results <- emmeans(MExt.LIKt, pairwise ~ Feedback, adjust="fdr")
- posthoc_results
- ### EXTEROCEPTIVE likert INTERACTIONS
- #STIMULUSINTESITY * FEEDBACK
- em_stimint <- emmeans(MExt.LIKt, ~ Feedback | StimInt, at = list(StimInt = c(-0.5, 0, 0.5)))
- summary(em_stimint)
- # Pairwise comparisons tra livelli di feedback, per ogni StimInt
- contrast(em_stimint, method = "pairwise", adjust = "fdr")
- # 1. Calcola le slope (trend) di StimInt per ciascun livello di Feedback
- slopes_feedback <- emtrends(MExt.LIKt, ~ Feedback, var = "StimInt")
- # 2. Riassunto delle stime: slope, SE, t, p, CI
- summary(slopes_feedback)
- test(slopes_feedback)
- # Contrasti sulle slope di StimInt tra condizioni di feedback
- contrast(slopes_feedback, method = "pairwise", adjust = "fdr")
- ### FEEDBACK * TRIAL
- # Calcolo delle slope dell’effetto di Trial all’interno di ogni livello di Feedback
- slopes_trial_by_feedback <- emtrends(MExt.LIKt, ~ Feedback, var = "Trial")
- summary(slopes_trial_by_feedback, infer = c(TRUE, TRUE)) # per avere anche t, p e CI
- # Contrasti tra le pendenze di Trial tra i diversi livelli di Feedback
- pairs(slopes_trial_by_feedback, adjust = "fdr")
- #plot(slopes_trial_by_feedback)
- ## what happens at each trial level
- feedback_by_trial_levels <- emmeans(MExt.LIKt, ~ Feedback | Trial,
- at = list(Trial = c(-0.5, 0, 0.5)))
- feedback_by_trial_levels
- pairs(feedback_by_trial_levels, adjust = "fdr")
- # STIMINT * TRIAL
- slopes_stimint_at <- emtrends(MExt.LIKt, ~ StimInt, var = "Trial", at = list(StimInt = c(-0.5, 0, 0.5)))
- summary(slopes_stimint_at, infer = c(TRUE, TRUE)) # p values diverso da zero?
- #differenze delle differenze
- contrast(slopes_stimint_at, method = "pairwise", adjust = "fdr")
- ################### VAS exteroceptive ###################
- MExt.VAS0 = lmer(VAS ~ Trial*Feedback*StimInt + (1|SSID),data = data2, REML = TRUE,
- control = lmerControl(optimizer = "optimx", calc.derivs = FALSE,
- optCtrl = list(method = "nlminb", starttests = FALSE, kkt = FALSE)))
- ## VAS
- MExt.VAS = lmer(VAS ~ Trial*Feedback*StimInt + (Trial+StimInt|SSID),data = data2, REML = TRUE,
- control = lmerControl(optimizer = "optimx", calc.derivs = FALSE,
- optCtrl = list(method = "nlminb", starttests = FALSE, kkt = FALSE)))
- model_comparison <- anova(MExt.VAS0, MExt.VAS)
- model_comparison
- # remove outliers (|standardized residuals| > 2 SDs)
- MExt.VASt = lmer(VAS ~ Trial*Feedback*StimInt + (Trial+StimInt|SSID),data = data2, REML = TRUE,
- subset = abs(scale(resid(MExt.VAS)))<2,
- control = lmerControl(optimizer = "optimx", calc.derivs = FALSE,
- optCtrl = list(method = "nlminb", starttests = FALSE, kkt = FALSE)))
- # residual analysis
- qqnorm(resid(MExt.VASt))
- qqline(resid(MExt.VASt))
- # show model results
- anova(MExt.VASt)
- summary(MExt.VASt)
- # save model results
- F_Ext.VAS = anova(MExt.VASt)
- T_Ext.VAS = data.frame(summary(MExt.VASt)$coefficients)
- posthoc_results <- emmeans(MExt.VASt, pairwise ~ Feedback, adjust="fdr")
- posthoc_results
- ### VAS
- # FEEDBACK*STIMINT i
- # Estimated marginal means di VAS per ciascun livello di Feedback, ai tre livelli di StimInt
- em_stimint <- emmeans(MExt.VASt, ~ Feedback | StimInt, at = list(StimInt = c(-0.5, 0, 0.5)))
- summary(em_stimint, infer = c(TRUE, TRUE))
- # Pairwise comparisons dentro a ogni StimInt
- contrast(em_stimint, method = "pairwise", by = "StimInt", adjust = "fdr")
- ## per differenze con zero e contrasti tra feedback (quanto l'increase del main effect stimint e' diverso per ogni feed)
- # 1. Calcola le slope (trend) di StimInt per ciascun livello di Feedback
- slopes_feedback <- emtrends(MExt.VASt, ~ Feedback, var = "StimInt")
- # 2. Riassunto delle stime: slope, SE, t, p, CI
- summary(slopes_feedback, infer = c(TRUE, TRUE))
- # Contrasti sulle slope di StimInt tra condizioni di feedback
- contrast(slopes_feedback, method = "pairwise", adjust = "fdr")
- # STIMINT * TRIAL
- slopes_stimint_at <- emtrends(MExt.VASt, ~ StimInt, var = "Trial", at = list(StimInt = c(-0.5, 0, 0.5)))
- summary(slopes_stimint_at, infer = c(TRUE, TRUE)) # p values diverso da zero?
- #differenze delle differenze
- contrast(slopes_stimint_at, method = "pairwise", adjust = "fdr")
- ## FEEDBACK * TRIAL
- # Calcolo delle slope dell’effetto di Trial all’interno di ogni livello di Feedback
- slopes_trial_by_feedback <- emtrends(MExt.VASt, ~ Feedback, var = "Trial")
- summary(slopes_trial_by_feedback, infer = c(TRUE, TRUE)) # per avere anche t, p e CI
- pairs(slopes_trial_by_feedback, adjust = "fdr")
- # Contrasti tra le pendenze di Trial tra i diversi livelli di Feedback
- trial_slope_contrasts <- pairs(slopes_trial_by_feedback, adjust = "fdr")
- summary(trial_slope_contrasts)
- plot(slopes_trial_by_feedback)
- ## what happens at each trial level
- feedback_by_trial_levels <- emmeans(MExt.VASt, ~ Feedback | Trial,
- at = list(Trial = c(-0.5, 0, 0.5)))
- feedback_by_trial_levels
- pairs(feedback_by_trial_levels, adjust = "fdr")
- ######################## pain response
- model_comparison <- anova(painrespBTW1, painrespBTW)
- model_comparison
- painrespBTW2 = lmer(HRPR ~ Trial*Feedback*StimInt*Exp + (Trial+StimInt|SSID),data = data, REML = TRUE,
- control = lmerControl(optimizer = "optimx", calc.derivs = FALSE,
- optCtrl = list(method = "nlminb", starttests = FALSE, kkt = FALSE)))
- painrespBTW1 = lmer(HRPR ~ Trial*Feedback*StimInt*Exp + (Trial|SSID),data = data, REML = TRUE,
- control = lmerControl(optimizer = "optimx", calc.derivs = FALSE,
- optCtrl = list(method = "nlminb", starttests = FALSE, kkt = FALSE)))
- painrespBTW = lmer(HRPR ~ Trial*Feedback*StimInt*Exp + (1|SSID),data = data, REML = TRUE,
- control = lmerControl(optimizer = "optimx", calc.derivs = FALSE,
- optCtrl = list(method = "nlminb", starttests = FALSE, kkt = FALSE)))
- # remove outliers (|standardized residuals| > 2 SDs)
- painrespBTW_n = lmer(HRPR ~ Trial*Feedback*StimInt*Exp + (1|SSID),data = data, REML = TRUE,
- subset = abs(scale(resid(painrespBTW)))<2,
- control = lmerControl(optimizer = "optimx", calc.derivs = FALSE,
- optCtrl = list(method = "nlminb", starttests = FALSE, kkt = FALSE)))
- # residual analysis
- qqnorm(resid(painrespBTW_n))
- qqline(resid(painrespBTW_n))
- # show model results
- anova(painrespBTW_n)
- summary(painrespBTW_n)
- # save model results
- F_Ext.VAS = anova(painrespBTW_n)
- T_Ext.VAS = data.frame(summary(painrespBTW_n)$coefficients)
- posthoc_results <- emmeans(F_Ext.VAS, pairwise ~ Exp, adjust="fdr")
- posthoc_results
- # Calcola i simple slopes di StimInt per ciascun livello di Exp
- emtrends(painrespBTW_n, specs = ~Exp, var = "StimInt") %>%
- summary(infer = c(TRUE, TRUE))
- # Calcolo dei simple slopes dell’effetto di Trial a ciascun livello di StimInt e per ciascun Exp
- emtrends(painrespBTW_n, specs = ~Exp | StimInt, var = "Trial", at = list(StimInt = c(-0.5, 0, 0.5))) %>%
- summary(infer = c(TRUE, TRUE))
- emtrends(painrespBTW_n, specs = ~Exp | Feedback, var = "StimInt") %>%
- summary(infer = c(TRUE, TRUE))
- # plot effects
- # If not installed yet
- # install.packages("effects")
- library(effects)
- # Get the effect of the 3-way interaction
- eff <- effect("Feedback:StimInt:Exp", painrespBTW_n)
- # Plot
- plot(eff, multiline = TRUE, ci.style = "bands",
- main = "Feedback × StimInt × Exp Interaction (Model-Based)",
- xlab = "StimInt", ylab = "Predicted HRPR")
- ####
- # If not installed yet
- # install.packages("ggeffects")
- library(ggeffects)
- library(ggplot2)
- # Get model-based predictions for the 3-way interaction
- preds <- ggpredict(painrespBTW_n, terms = c("StimInt", "Feedback", "Exp"))
- # Plot
- ggplot(preds, aes(x = x, y = predicted, color = group)) +
- geom_line(size = 1) +
- geom_point(size = 2) +
- geom_ribbon(aes(ymin = conf.low, ymax = conf.high, fill = group), alpha = 0.2, color = NA) +
- facet_wrap(~ facet) +
- labs(title = "Model-Based Interaction Plot: Feedback × StimInt × Exp",
- x = "StimInt",
- y = "Predicted HRPR",
- color = "Feedback",
- fill = "Feedback") +
- theme_minimal(base_size = 14)
- ###############################################
- library(ggeffects)
- library(ggplot2)
- # Get model-based predictions for the interaction between Trial and Exp
- preds <- ggpredict(painrespBTW_n, terms = c("Trial", "Exp"))
- # Plot
- ggplot(preds, aes(x = x, y = predicted, color = group)) +
- geom_line(size = 1) +
- geom_point(size = 2) +
- geom_ribbon(aes(ymin = conf.low, ymax = conf.high, fill = group), alpha = 0.2, color = NA) +
- labs(title = "Model-Based Interaction Plot: Trial × Exp",
- x = "Trial",
- y = "Predicted HRPR",
- color = "Exp",
- fill = "Exp") +
- theme_minimal(base_size = 14)
- #####
- # FEEDBACK * EXP
- library(emmeans)
- emmeans_FE <- emmeans(MBtw.VASt_N, ~ Feedback * Exp)
- summary(emmeans_FE)
- #Contrasti tra feedback entro ciascun esperimento
- contrast(emmeans_FE, method = "pairwise", by = "Exp", adjust = "fdr")
- #Contrasti di interazione (cioè: la differenza delle differenze)
- contrast(emmeans_FE, interaction = "pairwise")
- #########################
- correl_model = lmer(VAS ~ HR*Exp*Feedback + (1|SSID),data = data, REML = TRUE,
- control = lmerControl(optimizer = "optimx", calc.derivs = FALSE,
- optCtrl = list(method = "nlminb", starttests = FALSE, kkt = FALSE)))
- # remove outliers (|standardized residuals| > 2 SDs)
- correl_model_n = lmer(VAS ~ HR*Exp*Feedback + (1|SSID),data = data, REML = TRUE,
- subset = abs(scale(resid(correl_model)))<2,
- control = lmerControl(optimizer = "optimx", calc.derivs = FALSE,
- optCtrl = list(method = "nlminb", starttests = FALSE, kkt = FALSE)))
- # residual analysis
- qqnorm(resid(correl_model_n))
- qqline(resid(correl_model_n))
- # show model results
- anova(correl_model_n)
- summary(correl_model_n)
- # save model results
- F_Ext.VAS = anova(correl_model_n)
- T_Ext.VAS = data.frame(summary(correl_model_n)$coefficients)
- ###FEEDBACK
- emmeans_feedback <- emmeans(correl_model_n, ~ Feedback)
- # Confronti post hoc a coppie tra le condizioni di Feedback (con correzione Tukey)
- pairs(emmeans_feedback, adjust = "fdr")
- library(emmeans)
- ###FEEDBACK*vas
- emtrends(correl_model_n, ~ Feedback, var = "VAS")
- pairs(emtrends(correl_model_n, ~ Feedback, var = "VAS"), adjust = "fdr")
- # Post hoc: slope di VAS per ciascun tipo di Feedback
- em_slopes <- emtrends(correl_model_n, ~ Feedback, var = "VAS")
- # Visualizza le slopes
- summary(em_slopes)
- # Confronti post hoc tra le slopes
- pairs(em_slopes, adjust = "fdr")
- # slope di VAS → HR per ciascuna combinazione Feedback × Exp
- em_triple <- emtrends(correl_model_n, ~ Feedback * Exp, var = "VAS")
- # mostra le slopes
- summary(em_triple)
- # confronti post hoc tra combinazioni
- pairs(em_triple, adjust = "fdr")
mixed_models_all.R at commit c1c8721, under MIT · at the source
Overview
- Department of Psychology, Sapienza University of Rome, Rome, Italy
- School of Psychology, University of Aberdeen, Aberdeen, United Kingdom
- Department of Neuroscience, Imaging and Clinical Sciences, “G. d'Annunzio” University of Chieti-Pescara, Chieti, Italy
- Institute of Cognitive Sciences and Technologies, National Research Council, Rome, Italy
- Institute for Advanced Biomedical Technologies ‑ ITAB, “G. d'Annunzio” University of Chieti-Pescara, Chieti, Italy
- UdA-TechLab, Research Center, University “G. d’Annunzio” of Chieti-Pescara, Chieti, Italy
- Department of Psychology, “G. d’Annunzio” University of Chieti-Pescara, Chieti, Italy
Abstract
The experience of pain, like other interoceptive processes, has recently been conceptualized in terms of predictive coding and free energy frameworks. In these views, the brain integrates sensory, proprioceptive, and interoceptive signals to generate probabilistic inferences about upcoming events, which shape both the state and the perception of our inner body. Here, we ask whether it is possible to induce pain expectations by providing false faster (vs. slower) acoustic cardiac feedback before administering electrical cutaneous shocks. We test whether these expectations will shape both the perception of pain and the body’s physiological state toward prior predictions. Results confirmed that faster cardiac feedback elicited pain expectations that affected both perceptual pain judgments and the body’s physiological response. Perceptual pain judgments were biased toward the expected level of pain, such that participants illusorily perceived identical noxious stimuli as more intense and unpleasant. Physiological changes mirrored the predicted level of pain, such that participants’ actual cardiac response in anticipation of pain stimuli showed a deceleration in heart rate, in line with the well-known orienting cardiac response in anticipation of threatening stimuli (Experiment 1). In a control experiment, such perceptual and cardiac modulations were dramatically reduced when the feedback reproduced an exteroceptive, instead of interoceptive, cardiac feedback (Experiment 2). These findings show that cardiac perception can be understood as interoceptive inference that modulates both our perception and the physiological state of the body, thereby actively generating the interoceptive and autonomic consequences that have been predicted.
Reproduced under the paper's license (CC BY), from the paper cited above.
Repository
Its files are read in the Code ↔ Paper reader above.
EP171993/painperception
c1c8721f0e3d00fefc602ed32b84e24c218c56d3, 3 June 2026Availability: 1 check, the latest on 27 September 2026: the link answers
- 27 September 2026: the link answers
3 files
- mixed_models_all.R — R, 947 lines
- LICENSE — License, 21 lines
- README.md — Text, 2 lines
The paper's code and data availability statement is in the Data section.
Tracing map
Proposed by the machine: these links were found in the paper and verified at the source, without human review. The map will receive a Zenodo DOI once one of the paper's authors has validated it with their ORCID.
What the map holds:
- 1 repository of the authors' code, each at its verified commit, with its license and how the link was found in the paper;
- 1 script, each with its path and the digest of its content;
- no match between paragraphs and code yet;
- neither the text of the paper nor the code itself.
Its JSON (tracing-map.json) is deposited on Zenodo with its DOI once the map is validated.
Data
Datasets cited
Data availability
Anonymized raw ECG recordings underlying the results reported in this study are publicly available on OSF at: https://
The following dataset was generated:
Parrotta E. 2026. Exposure to false cardiac feedback alters pain perception and anticipatory cardiac frequency. Open Science Framework.
Reproduced under the paper's license (CC BY), from the paper cited above.
Versions
The history of this record: each version stored by the harvester or made by a correction of its authors or of the maintainers of its code, and what changed in its facts. The texts of the paper (its abstract, its availability statements) are not part of it; versions that changed only those are not listed.
Version 1, 27 September 2026: the first record
Recorded: type, language, journal, volume, pages, dates, 7 authors, 1 keyword, 8 MeSH terms, 4 funders, 141 references.
Cite
This paper
Parrotta, E., Bach, P., Pezzulo, G., Zaccaro, A., Perrucci, M. G., Costantini, M., & Ferri, F. (2026). Exposure to false cardiac feedback alters pain perception and anticipatory cardiac frequency. eLife, 12, RP90013. https://
BibTeX
@article{parrotta2026exp
author = {Parrotta, Eleonora and Bach, Patric and Pezzulo, Giovanni and Zaccaro, Andrea and Perrucci, Mauro Gianni and Costantini, Marcello and Ferri, Francesca},
title = {{Exposure to false cardiac feedback alters pain perception and anticipatory cardiac frequency}},
journal = {eLife},
year = {2026},
month = jun,
volume = {12},
pages = {RP90013},
publisher = {eLife Sciences Publications, Ltd},
issn = {2050-084X},
doi = {10.7554/
url = {https://
pmid = {42294597},
pmcid = {PMC13268646}
}
RIS
TY - JOUR
AU - Parrotta, Eleonora
AU - Bach, Patric
AU - Pezzulo, Giovanni
AU - Zaccaro, Andrea
AU - Perrucci, Mauro Gianni
AU - Costantini, Marcello
AU - Ferri, Francesca
TI - Exposure to false cardiac feedback alters pain perception and anticipatory cardiac frequency
T2 - eLife
J2 - Elife
PY - 2026
DA - 2026/
VL - 12
SP - RP90013
SN - 2050-084X
PB - eLife Sciences Publications, Ltd
DO - 10.7554/
UR - https://
LA - en
ER -
CSL-JSON
{
"id": "10.7554/
"type": "article-journal",
"title": "Exposure to false cardiac feedback alters pain perception and anticipatory cardiac frequency",
"container-title": "eLife",
"author": [
{
"family": "Parrotta",
"given": "Eleonora"
},
{
"family": "Bach",
"given": "Patric"
},
{
"family": "Pezzulo",
"given": "Giovanni"
},
{
"family": "Zaccaro",
"given": "Andrea"
},
{
"family": "Perrucci",
"given": "Mauro Gianni"
},
{
"family": "Costantini",
"given": "Marcello"
},
{
"family": "Ferri",
"given": "Francesca"
}
],
"container-title-short":
"volume": "12",
"page": "RP90013",
"DOI": "10.7554/
"PMID": "42294597",
"PMCID": "PMC13268646",
"ISSN": "2050-084X",
"publisher": "eLife Sciences Publications, Ltd",
"URL": "https://
"language": "en",
"issued": {
"date-parts": [
[
2026,
6,
15
]
]
}
}
The tracing map gets a citation of its own once an author has validated it and it has a DOI.
Similar papers
The papers with a page that share the most with this one: the tools found in their code, their categories, datasets, cited references and authors, the rarest counting most.
- [1] doi:10.1038/s41467-026-74743-0 [code]
- Meta-analytic evidence for distinct neural correlates of conditioned versus verbally induced placebo analgesia.Journal: Nature communicationsIn common: lmerTest, lme4, ggplot2, pain, 8 references
- [2] doi:10.3389/fnhum.2026.1820376 [code]
- The neural dynamics of political socio-pragmatic violations: an ERP study.Journal: Frontiers in human neuroscienceIn common: emmeans, lmerTest, lme4, 1 other tool, 3 references
- [3] doi:10.1038/s41598-026-52930-9
- Cardiac systole is associated with enhanced go responding in an orthogonalized go/
nogo task. Journal: Scientific reportsIn common: cognitive, 6 references - [4] doi:10.1371/journal.pone.0355165 [code]
- Pupillary dynamics during hands-off L2 driving and transitions of control under high cognitive load.Journal: PloS oneIn common: brms, emmeans, lmerTest, 2 other tools, cognitive
- [5] doi:10.1016/j.isci.2026.116747 [code]
- Age and loneliness relate to reduced trust learning and alterations in amygdala function.Journal: iScienceIn common: brms, emmeans, lmerTest, 2 other tools, cognitive
- [6] doi:10.1038/s41467-026-73865-9 [code]
- Histamine shapes the neurocomputational dynamics of human learning.Journal: Nature communicationsIn common: brms, emmeans, lmerTest, 2 other tools, cognitive
- [7] doi:10.1523/eneuro.0316-25.2026 [code]
- Neural Mechanisms of Self-Generated Action Sequences.Journal: eNeuroIn common: brms, emmeans, lmerTest, 2 other tools, cognitive
- [8] doi:10.1093/nc/niag046 [code]
- Awareness of being: a computational neurophenomenological model of mindfulness, mind-wandering, and meta-attentional control.Journal: Neuroscience of consciousnessIn common: 6 references
- [9] doi:10.1093/braincomms/fcag120 [code]
- The heartbeat evoked potential and the prediction of functional seizure semiology.Journal: Brain communicationsIn common: 5 references
- [10] doi:10.1038/s41467-026-72916-5 [code]
- Precision fMRI reveals that the language network exhibits adult-like left-hemispheric lateralization by 4 years of age.Journal: Nature communicationsIn common: brms, emmeans, lmerTest, 2 other tools
Contribute
The authors of this paper can claim it, correct its record and validate its tracing map, and the maintainers of its code (its owner, or a public member of its organization) correct what it says of their repository; anyone signed in can ask for its removal. Every request goes to OSCR's own machine, which answers it; your account page follows them.
Sign in with ORCID to claim this paper as one of its authors, correct its record or validate its tracing map: when the paper's metadata lists your ORCID iD, you are recognized at once. Maintainers of its code: sign in with GitHub, then claim the repository on your account page.
Claim this paper
Correct its record
Say what each link of this record is, remove the ones that are not the paper's, add the ones that are missing. The correction becomes a new version of the record, in its Versions section.
Validate its tracing map
You validate the map as this page shows it: 1 repository of the authors' code, each at its verified commit and with its license, 1 script, and 0 matches between paragraphs and code (see the Code and Map sections). It then receives a DOI on Zenodo, with you (your ORCID iD) and OSCR as its creators; the code itself is not deposited.
The map's fingerprint: sha256:b679567fede110b6…
Add the badge to its README
The badge links the code to this page. Copy one of these into the README of the paper's code: only you decide where it goes, and nothing is changed for you.
Markdown
[, paste the snippet at the top, then “Commit changes…” and, to review it first, “Create a new branch and start a pull request”. You open the pull request; OSCR asks for no permission.
Request its removal
To ask OSCR to remove this record, the copies of its authors' scripts or its tracing map, use the removal request page: signed in, you say who you are, what to remove and why, then review and confirm the request. Published rules decide every request (how).
Discussion, reproductions, activity
Discussion: questions and error reports about this paper and its code, from signed-in readers and its authors. It opens with sign-in.
Reproductions: reports from readers who ran the authors' code: what they reproduced, with which environment, commit and data. It opens with sign-in.
Activity: what happens around this paper: new versions of its record, its map's validation, discussions and reproductions. It opens with sign-in.
