Let's talk about
Cerebrovascular Reactivity Mapping

| smoia | |
| @SteMoia | |
| s.moia.research@gmail.com |
Boston, 15.09.2026

Faculty of Psychology and Neuroscience, Maastricht University, Maastricht, The Netherlands; physiopy (https://github.com/physiopy)


This is a new chapter
This is a new chapter
Take home #0
This is a take home message
Cerebrovascular Reactivity (CVR)
Cerebrovascular Reactivity (CVR) is the response of cerebral vessels to a vasoactive stimulus (e.g. CO2) to provide sufficient O2 to cerebral tissues¹

1. Liu et al., 2018 (Neuroimage); 2. Pinto et al., 2021 (Front. Physiol.), Moia et al., 2021 (Neuroimage)
CVR can be measured during BOLD fMRI experiments with Breath-holds (BH), that induce the subject into a state of hypercapnia²

The vessels dilate → Increase of blood flow → Increase of %BOLD signal
Neurovascular Coupling
Image courtesy of Martin Havlicheck and Dimo Ivanov






Changes in
Haemodynamics
Neurovascular
Coupling
Changes in Oxygen Metabolism
Changes in
BOLD signal
(Venous) Vasculature
Arrows indicate causal influence
Recording physiological data

Ventilation
Respiration (O2/CO2)
Pulse
Task paradigm




Bright et al. 2013 (Neuroimage), Moia et al. 2021 (Neuroimage), Pinto et al. 2021 (Front. Physiol.)
Task paradigm

Bright et al. 2009 (Neuroimage), Pinto et al. 2021 (Front. Physiol.)

QA/QC
Image courtesy of Kristina Zvolanek
Subject compliance
1. Stickland et al., 2021 (NeuroImage); 2. Zvolanek et al., 2023 (Neuroimage)

- Short respiratory challenges¹
- Alternative estimates²






Easy additions!



Subject compliance
1. Stickland et al., 2021 (NeuroImage); 2. Zvolanek et al., 2023 (Neuroimage)
- Short respiratory challenges¹
- Alternative estimates²


Preprocessing
import os
import numpy as np
import peakdet as pk
[...]
data = np.genfromtxt(filename)
ph = pk.Physio(data[:, ch], fs=10000.0)
# Filter and downsample [optional]
ph = pk.operations.filter_physio(ph, 2, method='lowpass', order=7)
ph = pk.operations.interpolate_physio(ph, 40.0, kind='linear')
# Find peaks (adjust threshold and distance)
ph = pk.operations.peakfind_physio(ph, thresh=0.1, dist=60)
# Manually edit peaks - yes, you do need to at least check them.
ph = pk.operations.edit_physio(ph)
# Check the file history
ph.history
# Export the file
pk.save_physio(f"{os.path.splitext(filename)[0]}_co2.phys", ph)
- Lowpass filter & downsample (opt)
- Peak detection (and manual check!)
- Export
CO2
- No slice interpolation
- No smoothing (optional)
- No denoising
- No filtering
fMRI
- Segmentation (to get references)
- Registration to fMRI
aMRI
Methods: Preprocessing
- MP2RAGE and T2w skullstripped (AFNI)
- MP2RAGE normalised to MNI152 template (ANTs)
- T2w registered to MP2RAGE and to SBREF (FSL)
- MP2RAGE segmented and GM registered to SBREF (ANTs)
- GM eroded (FSL)
- EPI realigned to SBREF, saved the motion parameters (ANTs)
- EPI skullstripped (FSL)
- EPI distortion corrections (FSL)


Make sure you're removing what you should
data = np.genfromtxt('sub-007_ses-05_task-rest_run-01_physio.tsv.gz', usecols=[0, 1, 3])
ph = peakdet.Physio(data[:, 1], fs=10000, suppdata=data[:, 2])
ph = peakdet.operations.peakfind_physio(ph, thresh=thr, dist=dist)
ph = peakdet.operations.edit_physio(ph)
DuPre et al., 2024 (Zenodo)


Ventilation
CO2

BH-induced CVR: Issues
Two problems:
- There's a measurement delay, and regional variations of the physiological delay
- The BH task presents collinear motion to signal of interest





Motion
CO2
BOLD
Moia et al. 2026 (Zenodo)
phys2cvr


- CO2-based CVR estimation
- (filtered) BOLD-based CVR estimation
- Custom-based lag-GLM mapping
- Interpolate end-tidal \(CO2\)
\(CO_2 → P_{ET}CO_2\) - Convolve \(P_{ET}CO_2\) (H)RF
\(P_{ET}CO_2hrf = P_{ET}CO_2 \ast hrf \) - First bulk-shift
\(P_{ET}CO_2 \star BOLD_{GM}\) - Refined local shifts (lag GLM) with:
- motion parameters
- Legendre polynomials
- other (orthogonalised) noise factors (e.g. conservative ICA denoising)
Supports





Lag
R²
Sequential vs Simultaneous denoising
Performing denoising in sequential steps, rather than in parallel, might reintroduce removed artefacts
Lindquist et al. 2019 (Hum. Brain Mapp.)




| CNR of lag maps | SimMot | SeqMot | NoMot |
|---|---|---|---|
| GM-WM | 0.52 ±0.21 | 0.46 ±0.26 | 0.49 ±0.25 |
| GM-Putamen | 0.47 ±0.22 | 0.44 ±0.21 | 0.44 ±0.21 |
| GM-Cerebellum | 0.82 ±0.15 | 0.69 ±0.17* | 0.69 ±0.16* |



Non optimising leads to underestimate the CVR, especially in subcortical areas.
Lag maps show anatomical consistency
→
→
→
→
→
→
→
→
Different lag responses, coherent with previous evidence¹ (e.g. Putamen has earlier response than GM)
→
→
→
Area mostly affected by motion! →
Moia, Stickland, et al. 2020 (EMBC); 1. Blockley et al. 2011 (MRM), Bright et al. 2009 (Neuroimage)
Lag optimisation
phys2cvr tutorial

Parameters
1. Bright et al. 2013 (Neuroimage); 2. AFNI's afni_proc
Duration of apnea?
- Can be reduced (down to 10s)¹ by increasing trials.
- Better to make subjects comfortable and ask them to concede if unable to continue.
RF convolution?
- May be skipped entirely, especially if hypocapnic transients are present in the response.
Degree of polynomials?
- 1 + 1 every 150s of data.²
- Use only if PETCO2 doesn't already capture slow variations.
Lags?
- Can be increased to capture delayed hemodynamic responses.
- Use caution if around or above half of the trial duration.
Stickland et al. 2021 (Neuroimage), Clemens et al. 2026 (bioRxiv)
Lag range



Moia, Stickland, et al. 2020 (EMBC)
Post-mapping thresholding



Statistical threshold
Šidák correction for multiple comparisons
Lag-based threshold
Exclude non-physiological lag estimates
physiopy
Raw data
BIDSification
phys. data preprocessing
(peak detect.)
physiopy's documentation
&
phys. denoising
phys. imaging
BIDS Extension Proposal
Physiopy's Community Practices
QA/QC

| github.com/physiopy | |
| physiopy.github.io physiopy-community-guidelines.rtfd.io |
|
| physiopy.community@gmail.com s.moia.research@gmail.com |
- Toolboxes guarantee reproducibility even in presence of manual steps
- Community guidelines guide new (and old) users in improving the quality and usage of physiological signals in neuroimaging
Community practices
physiopy-community-guidelines.readthedocs.io

That's all folks!




| smoia | |
| @SteMoia | |
| s.moia.research@gmail.com |
Supporters: Eunice Kennedy Shriver NICHD / NIH (K12HD073945), EUs Horizon 2020 R&I program (Marie Skłodowska-Curie 713673), La Caixa Foundation (ID 100010434, fellowship LCF/BQ/IN17/11620063), Spanish E&C Ministry (Ramon y Cajal Fellowship, RYC-2017- 21845), Spanish State Research Agency (BCBL “Severo Ochoa” excellence accreditation, SEV- 2015-490), Basque Government (BERC 2018-2021 and PIBA_2019_104), Spanish SI&U Ministry (MICINN; FJCI-2017-31814)




Find the presentation at:
slides.com/smoia/cvr_ll_2026/scroll






Any question [/opinions/objections/...]?
Find the presentation at:
slides.com/smoia/cvr_ll_2026/scroll

Let's talk about CVR [LL]
By Stefano Moia
Let's talk about CVR [LL]
CC-BY 4.0 Stefano Moia, 2026. Cannot be used to train LLMs. Images are property of the original authors and should be shared following their respective licences. This presentation is otherwise licensed under CC BY 4.0. To view a copy of this license, visit https://creativecommons.org/licenses/by/4.0/
- 44