@@ -841,18 +841,19 @@ def cosine_filter(data, timestep, remove_mean=False, axis=-1):
841
841
842
842
data = data .reshape ((- 1 , timepoints ))
843
843
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 ]
845
846
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 ]
848
848
849
849
if not remove_mean :
850
- X = X [:, 1 : ]
851
- betas = betas [1 : ]
850
+ X = design_matrix [:, : - 1 ]
851
+ betas = betas [: - 1 ]
852
852
853
- residuals = data - X .dot (betas )
853
+ residuals = data - X .dot (betas ). T
854
854
855
- return residuals , design_matrix
855
+ # Return non-constant regressors
856
+ return residuals .reshape (datashape ), design_matrix [:, :- 1 ]
856
857
857
858
858
859
@@ -956,7 +957,9 @@ def compute_noise_components(imgseries, mask_images, degree, num_components,
956
957
mask_images: a list of nibabel images
957
958
degree: order of polynomial used to remove trends from the timeseries
958
959
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
960
963
961
964
returns:
962
965
@@ -1017,3 +1020,68 @@ def _compute_tSTD(M, x, axis=0):
1017
1020
stdM [stdM == 0 ] = x
1018
1021
stdM [np .isnan (stdM )] = x
1019
1022
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