Skip to content

Commit 66652a8

Browse files
committed
Copy in nipy functions, transpose correctly
1 parent 42f5c46 commit 66652a8

File tree

1 file changed

+76
-8
lines changed

1 file changed

+76
-8
lines changed

nipype/algorithms/confounds.py

Lines changed: 76 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -841,18 +841,19 @@ def cosine_filter(data, timestep, remove_mean=False, axis=-1):
841841

842842
data = data.reshape((-1, timepoints))
843843

844-
design_matrix = dmtx_light(timestep * np.arange(timepoints))
844+
frametimes = timestep * np.arange(timepoints)
845+
design_matrix = _full_rank(_cosine_drift(128, frametimes))[0]
845846

846-
X = np.hstack(np.ones((timepoints, 1)), design_matrix)
847-
betas = np.linalg.lstsq(X, data)[0]
847+
betas = np.linalg.lstsq(design_matrix, data.T)[0]
848848

849849
if not remove_mean:
850-
X = X[:, 1:]
851-
betas = betas[1:]
850+
X = design_matrix[:, :-1]
851+
betas = betas[:-1]
852852

853-
residuals = data - X.dot(betas)
853+
residuals = data - X.dot(betas).T
854854

855-
return residuals, design_matrix
855+
# Return non-constant regressors
856+
return residuals.reshape(datashape), design_matrix[:, :-1]
856857

857858

858859

@@ -956,7 +957,9 @@ def compute_noise_components(imgseries, mask_images, degree, num_components,
956957
mask_images: a list of nibabel images
957958
degree: order of polynomial used to remove trends from the timeseries
958959
num_components: number of noise components to return
959-
high_pass_filter:
960+
high_pass_filter: high-pass-filter data with discrete cosine basis
961+
(run before polynomial detrend)
962+
repetition_time: time (in sec) between volume acquisitions
960963
961964
returns:
962965
@@ -1017,3 +1020,68 @@ def _compute_tSTD(M, x, axis=0):
10171020
stdM[stdM == 0] = x
10181021
stdM[np.isnan(stdM)] = x
10191022
return stdM
1023+
1024+
1025+
# _cosine_drift and _full_rank copied from nipy/modalities/fmri/design_matrix
1026+
#
1027+
# Nipy release: 0.4.1
1028+
1029+
def _cosine_drift(period_cut, frametimes):
1030+
"""Create a cosine drift matrix with periods greater or equals to period_cut
1031+
1032+
Parameters
1033+
----------
1034+
period_cut: float
1035+
Cut period of the low-pass filter (in sec)
1036+
frametimes: array of shape(nscans)
1037+
The sampling times (in sec)
1038+
1039+
Returns
1040+
-------
1041+
cdrift: array of shape(n_scans, n_drifts)
1042+
cosin drifts plus a constant regressor at cdrift[:,0]
1043+
1044+
Ref: http://en.wikipedia.org/wiki/Discrete_cosine_transform DCT-II
1045+
"""
1046+
len_tim = len(frametimes)
1047+
n_times = np.arange(len_tim)
1048+
hfcut = 1./ period_cut # input parameter is the period
1049+
1050+
dt = frametimes[1] - frametimes[0] # frametimes.max() should be (len_tim-1)*dt
1051+
order = int(np.floor(2*len_tim*hfcut*dt)) # s.t. hfcut = 1/(2*dt) yields len_tim
1052+
cdrift = np.zeros((len_tim, order))
1053+
nfct = np.sqrt(2.0/len_tim)
1054+
1055+
for k in range(1, order):
1056+
cdrift[:,k-1] = nfct * np.cos((np.pi/len_tim)*(n_times + .5)*k)
1057+
1058+
cdrift[:,order-1] = 1. # or 1./sqrt(len_tim) to normalize
1059+
return cdrift
1060+
1061+
1062+
1063+
def _full_rank(X, cmax=1e15):
1064+
"""
1065+
This function possibly adds a scalar matrix to X
1066+
to guarantee that the condition number is smaller than a given threshold.
1067+
1068+
Parameters
1069+
----------
1070+
X: array of shape(nrows, ncols)
1071+
cmax=1.e-15, float tolerance for condition number
1072+
1073+
Returns
1074+
-------
1075+
X: array of shape(nrows, ncols) after regularization
1076+
cmax=1.e-15, float tolerance for condition number
1077+
"""
1078+
U, s, V = np.linalg.svd(X, 0)
1079+
smax, smin = s.max(), s.min()
1080+
c = smax / smin
1081+
if c < cmax:
1082+
return X, c
1083+
warn('Matrix is singular at working precision, regularizing...')
1084+
lda = (smax - cmax * smin) / (cmax - 1)
1085+
s = s + lda
1086+
X = np.dot(U, np.dot(np.diag(s), V))
1087+
return X, cmax

0 commit comments

Comments
 (0)