Odd XCP-D denoised timeseries

Hi there,

I have recently run the XCP-D pipeline (stable release 0.4) over a set of preprocessed RS fMRI scans (via fMRIPrep v22.1.1). Main XCP-D arguments used:

--nuisance-regressors 36P
--smoothing 6
--dummy-scans 4
--fd-thresh 0.5

Reviewing the resulting denoised BOLD data, I have some few cases showing rather strange results (~5% of the whole dataset).

Some results present a very high or low postprocessed BOLD signal intensity values in the first volumes/timeseries:

While some other cases show the same peculiarity but for the last volumes/timeseries:

I have reviewed for those cases both the raw image data as well as the fMRIPrep outputs (preprocessed BOLD) but they do look normal to me.

Any idea of what might be going on here?

(PS: all data was acquired with a Philips MRI scanner, same scanning protocol)

Thanks in advance,

It seems like it could be an issue with the bandpass filter. What settings did you use?

No bandpass filtering settings were explicitly set. I’ve just used the default filtering parameters (i.e. bandpass range 0.01-0.08 Hz with a order 2 Butterworth filter).

Full command call:

xcp_d ${PREP_INDIR} ${OUT_DIR} participant --task-id rest \
                                           --work_dir ${WORK_DIR} \
                                           --input-type fmriprep \
                                           --smoothing 6 \
                                           --despike \
                                           --dummy-scans 4 \
                                           --fd-thresh 0.5 
                                           --nuisance-regressors 36P \
                                           --dcan-qc \
                                           --nthreads 4

I have finally had some time to put on this issue to do some more tests.

Apparently, it looks like -as you @tsalo suggested- it might be related to the bandpass filtering step.

The high-motion volumes identified to be excluded from the BOLD data as outliers in the temporal censoring stage, are replaced by interpolations of the BOLD signal at the bandpass filtering step.
This interpolation procedure might be in my opinion what produces such bad outcomes for certain cases. Particularly, cases where a substantial amount of adjacent volumes are being removed close to the beginning/end of the whole time-series.

If I run xcp-d disabling the band-pass filter for those affected cases, the results look much closer to the expected ones but of course I have unfiltered data.

I wonder what would you recommend at this stage, perhaps find a better and more resilient interpolation approach or simply discard the bandpass filtering step of the BOLD signal?


Thanks for the detailed report. So it seems like XCP-D should just not perform interpolation for censored volumes at the beginning and end of the time series. Does that sound right to you?

If you want to try out different bandpass filtering options, you can run XCP-D 0.5.0 with --dcan-qc and --disable-bandpass-filter, which will produce desc-interpolated_bold files that include interpolated data, but without bandpass filtering. Then you can do what you want to the data before applying a temporal filter.

EDIT: I’ve opened an issue on GitHub, since this definitely seems like a fixable bug on XCP-D’s end. Interpolating volumes at beginning/end of scan may lead to artifacts · Issue #949 · PennLINC/xcp_d · GitHub

1 Like

Great, thank you so much @tsalo.

It definitely looks like when the interpolation goes wrong, there are censored volumes at the beginning/end of the timeseries (even if there’s only one single volume).

Minimally understanding the process underneath this (cubic spline) interpolation procedure I suspect that, for those troubled cases, the interpolation becomes an extrapolation process instead. That is, asking to predict values outside the range of data available (instead of finding intermediate values within as expected).
My guess is (disclaimer: I haven’t look at the interpolation code) that cubic splines are not suited to extrapolate beyond the data set, the spline might not follow the trend of the points as seen in our use-case were it goes bananas.

Hopefully this issue can be fixed in the XCP-D codebase adding a more robust interpolation method or improving the former one. That would be the ideal solution to us, otherwise we will search ways to workaround it. One being what you suggested about working with the desc-interpolated_bold files. Another option we internally discussed could be adding cosine-related regressors (available via fMRIPrep) to the list of nuisance regressors and skip temporal filtering and, hence, the interpolation.


Rather than support extrapolation, I think the best/easiest thing would be to just not interpolate high-motion volumes if they’re at the beginning/end of the run.

That makes sense, indeed.

I have been traversing the pipeline code in charge of the interpolation process. Heading first to nilearn _interpolate_volumes() function and then to scipy scipy.interpolate.CubicSpline (scipy.interpolate.CubicSpline — SciPy v1.11.3 Manual) class, were the interpolation actually takes place.

Luckily, there is -in my opinion- an easy fix following your approach. CubicSpline class has a parameter for enabling extrapolation set by default to True which I think could be set to False:

from scipy.interpolate import CubicSpline
cubic_spline_fitter = CubicSpline(remained_vol, remained_x, extrapolate=False)

Some quick example, showing an original interpolation of first 5 volumes VERSUS an interpolation with extrapolate parameter to False,

Original data,

Interpolation as is (with extrapolation param. enabled by default),

Interpolation with extrapolation param. disabled,

Perhaps I am getting too technical, I can place this post in the Github issue you just opened if you prefer.

That’s a really great catch. If you’re willing, it would be great if you could open an issue in the nilearn repo.

EDIT: Also, yes, posting in the XCP-D GitHub issue would be great.