rapidtide 3.0.10__py3-none-any.whl → 3.1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- rapidtide/Colortables.py +492 -27
- rapidtide/OrthoImageItem.py +1053 -47
- rapidtide/RapidtideDataset.py +1533 -86
- rapidtide/_version.py +3 -3
- rapidtide/calccoherence.py +196 -29
- rapidtide/calcnullsimfunc.py +191 -40
- rapidtide/calcsimfunc.py +245 -42
- rapidtide/correlate.py +1210 -393
- rapidtide/data/examples/src/testLD +56 -0
- rapidtide/data/examples/src/testalign +1 -1
- rapidtide/data/examples/src/testdelayvar +0 -1
- rapidtide/data/examples/src/testfmri +19 -1
- rapidtide/data/examples/src/testglmfilt +5 -5
- rapidtide/data/examples/src/testhappy +30 -1
- rapidtide/data/examples/src/testppgproc +17 -0
- rapidtide/data/examples/src/testrolloff +11 -0
- rapidtide/data/models/model_cnn_pytorch/best_model.pth +0 -0
- rapidtide/data/models/model_cnn_pytorch/loss.png +0 -0
- rapidtide/data/models/model_cnn_pytorch/loss.txt +1 -0
- rapidtide/data/models/model_cnn_pytorch/model.pth +0 -0
- rapidtide/data/models/model_cnn_pytorch/model_meta.json +68 -0
- rapidtide/data/reference/JHU-ArterialTerritoriesNoVent-LVL1_space-MNI152NLin2009cAsym_2mm.nii.gz +0 -0
- rapidtide/data/reference/JHU-ArterialTerritoriesNoVent-LVL1_space-MNI152NLin2009cAsym_2mm_mask.nii.gz +0 -0
- rapidtide/decorators.py +91 -0
- rapidtide/dlfilter.py +2225 -108
- rapidtide/dlfiltertorch.py +4843 -0
- rapidtide/externaltools.py +327 -12
- rapidtide/fMRIData_class.py +79 -40
- rapidtide/filter.py +1899 -810
- rapidtide/fit.py +2004 -574
- rapidtide/genericmultiproc.py +93 -18
- rapidtide/happy_supportfuncs.py +2044 -171
- rapidtide/helper_classes.py +584 -43
- rapidtide/io.py +2363 -370
- rapidtide/linfitfiltpass.py +341 -75
- rapidtide/makelaggedtcs.py +211 -20
- rapidtide/maskutil.py +423 -53
- rapidtide/miscmath.py +827 -121
- rapidtide/multiproc.py +210 -22
- rapidtide/patchmatch.py +234 -33
- rapidtide/peakeval.py +32 -30
- rapidtide/ppgproc.py +2203 -0
- rapidtide/qualitycheck.py +352 -39
- rapidtide/refinedelay.py +422 -57
- rapidtide/refineregressor.py +498 -184
- rapidtide/resample.py +671 -185
- rapidtide/scripts/applyppgproc.py +28 -0
- rapidtide/simFuncClasses.py +1052 -77
- rapidtide/simfuncfit.py +260 -46
- rapidtide/stats.py +540 -238
- rapidtide/tests/happycomp +9 -0
- rapidtide/tests/test_dlfiltertorch.py +627 -0
- rapidtide/tests/test_findmaxlag.py +24 -8
- rapidtide/tests/test_fullrunhappy_v1.py +0 -2
- rapidtide/tests/test_fullrunhappy_v2.py +0 -2
- rapidtide/tests/test_fullrunhappy_v3.py +1 -0
- rapidtide/tests/test_fullrunhappy_v4.py +2 -2
- rapidtide/tests/test_fullrunrapidtide_v7.py +1 -1
- rapidtide/tests/test_simroundtrip.py +8 -8
- rapidtide/tests/utils.py +9 -8
- rapidtide/tidepoolTemplate.py +142 -38
- rapidtide/tidepoolTemplate_alt.py +165 -44
- rapidtide/tidepoolTemplate_big.py +189 -52
- rapidtide/util.py +1217 -118
- rapidtide/voxelData.py +684 -37
- rapidtide/wiener.py +19 -12
- rapidtide/wiener2.py +113 -7
- rapidtide/wiener_doc.py +255 -0
- rapidtide/workflows/adjustoffset.py +105 -3
- rapidtide/workflows/aligntcs.py +85 -2
- rapidtide/workflows/applydlfilter.py +87 -10
- rapidtide/workflows/applyppgproc.py +522 -0
- rapidtide/workflows/atlasaverage.py +210 -47
- rapidtide/workflows/atlastool.py +100 -3
- rapidtide/workflows/calcSimFuncMap.py +294 -64
- rapidtide/workflows/calctexticc.py +201 -9
- rapidtide/workflows/ccorrica.py +97 -4
- rapidtide/workflows/cleanregressor.py +168 -29
- rapidtide/workflows/delayvar.py +163 -10
- rapidtide/workflows/diffrois.py +81 -3
- rapidtide/workflows/endtidalproc.py +144 -4
- rapidtide/workflows/fdica.py +195 -15
- rapidtide/workflows/filtnifti.py +70 -3
- rapidtide/workflows/filttc.py +74 -3
- rapidtide/workflows/fitSimFuncMap.py +206 -48
- rapidtide/workflows/fixtr.py +73 -3
- rapidtide/workflows/gmscalc.py +113 -3
- rapidtide/workflows/happy.py +813 -201
- rapidtide/workflows/happy2std.py +144 -12
- rapidtide/workflows/happy_parser.py +149 -8
- rapidtide/workflows/histnifti.py +118 -2
- rapidtide/workflows/histtc.py +84 -3
- rapidtide/workflows/linfitfilt.py +117 -4
- rapidtide/workflows/localflow.py +328 -28
- rapidtide/workflows/mergequality.py +79 -3
- rapidtide/workflows/niftidecomp.py +322 -18
- rapidtide/workflows/niftistats.py +174 -4
- rapidtide/workflows/pairproc.py +88 -2
- rapidtide/workflows/pairwisemergenifti.py +85 -2
- rapidtide/workflows/parser_funcs.py +1421 -40
- rapidtide/workflows/physiofreq.py +137 -11
- rapidtide/workflows/pixelcomp.py +208 -5
- rapidtide/workflows/plethquality.py +103 -21
- rapidtide/workflows/polyfitim.py +151 -11
- rapidtide/workflows/proj2flow.py +75 -2
- rapidtide/workflows/rankimage.py +111 -4
- rapidtide/workflows/rapidtide.py +272 -15
- rapidtide/workflows/rapidtide2std.py +98 -2
- rapidtide/workflows/rapidtide_parser.py +109 -9
- rapidtide/workflows/refineDelayMap.py +143 -33
- rapidtide/workflows/refineRegressor.py +682 -93
- rapidtide/workflows/regressfrommaps.py +152 -31
- rapidtide/workflows/resamplenifti.py +85 -3
- rapidtide/workflows/resampletc.py +91 -3
- rapidtide/workflows/retrolagtcs.py +98 -6
- rapidtide/workflows/retroregress.py +165 -9
- rapidtide/workflows/roisummarize.py +173 -5
- rapidtide/workflows/runqualitycheck.py +71 -3
- rapidtide/workflows/showarbcorr.py +147 -4
- rapidtide/workflows/showhist.py +86 -2
- rapidtide/workflows/showstxcorr.py +160 -3
- rapidtide/workflows/showtc.py +159 -3
- rapidtide/workflows/showxcorrx.py +184 -4
- rapidtide/workflows/showxy.py +185 -15
- rapidtide/workflows/simdata.py +262 -36
- rapidtide/workflows/spatialfit.py +77 -2
- rapidtide/workflows/spatialmi.py +251 -27
- rapidtide/workflows/spectrogram.py +305 -32
- rapidtide/workflows/synthASL.py +154 -3
- rapidtide/workflows/tcfrom2col.py +76 -2
- rapidtide/workflows/tcfrom3col.py +74 -2
- rapidtide/workflows/tidepool.py +2972 -133
- rapidtide/workflows/utils.py +19 -14
- rapidtide/workflows/utils_doc.py +293 -0
- rapidtide/workflows/variabilityizer.py +116 -3
- {rapidtide-3.0.10.dist-info → rapidtide-3.1.dist-info}/METADATA +10 -9
- {rapidtide-3.0.10.dist-info → rapidtide-3.1.dist-info}/RECORD +141 -122
- {rapidtide-3.0.10.dist-info → rapidtide-3.1.dist-info}/entry_points.txt +1 -0
- {rapidtide-3.0.10.dist-info → rapidtide-3.1.dist-info}/WHEEL +0 -0
- {rapidtide-3.0.10.dist-info → rapidtide-3.1.dist-info}/licenses/LICENSE +0 -0
- {rapidtide-3.0.10.dist-info → rapidtide-3.1.dist-info}/top_level.txt +0 -0
rapidtide/resample.py
CHANGED
|
@@ -31,14 +31,18 @@ with warnings.catch_warnings():
|
|
|
31
31
|
else:
|
|
32
32
|
pyfftwpresent = True
|
|
33
33
|
|
|
34
|
-
import
|
|
34
|
+
from typing import Any, Callable, Optional, Tuple, Union
|
|
35
|
+
|
|
36
|
+
import matplotlib.pyplot as plt
|
|
35
37
|
import scipy as sp
|
|
38
|
+
from numpy.typing import ArrayLike, NDArray
|
|
36
39
|
from scipy import fftpack, signal
|
|
37
40
|
|
|
38
41
|
import rapidtide.filter as tide_filt
|
|
39
42
|
import rapidtide.fit as tide_fit
|
|
40
43
|
import rapidtide.io as tide_io
|
|
41
44
|
import rapidtide.util as tide_util
|
|
45
|
+
from rapidtide.decorators import conditionaljit, conditionaljit2
|
|
42
46
|
|
|
43
47
|
if pyfftwpresent:
|
|
44
48
|
fftpack = pyfftw.interfaces.scipy_fftpack
|
|
@@ -50,125 +54,77 @@ import warnings
|
|
|
50
54
|
|
|
51
55
|
warnings.simplefilter(action="ignore", category=RuntimeWarning)
|
|
52
56
|
|
|
53
|
-
# ---------------------------------------- Global constants -------------------------------------------
|
|
54
|
-
donotbeaggressive = True
|
|
55
|
-
|
|
56
|
-
# ----------------------------------------- Conditional imports ---------------------------------------
|
|
57
|
-
try:
|
|
58
|
-
from numba import jit
|
|
59
|
-
except ImportError:
|
|
60
|
-
donotusenumba = True
|
|
61
|
-
else:
|
|
62
|
-
donotusenumba = False
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
def conditionaljit():
|
|
66
|
-
def resdec(f):
|
|
67
|
-
if donotusenumba:
|
|
68
|
-
return f
|
|
69
|
-
return jit(f, nopython=True)
|
|
70
|
-
|
|
71
|
-
return resdec
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
def conditionaljit2():
|
|
75
|
-
def resdec(f):
|
|
76
|
-
if donotusenumba or donotbeaggressive:
|
|
77
|
-
return f
|
|
78
|
-
return jit(f, nopython=True)
|
|
79
|
-
|
|
80
|
-
return resdec
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
def disablenumba():
|
|
84
|
-
global donotusenumba
|
|
85
|
-
donotusenumba = True
|
|
86
|
-
|
|
87
|
-
|
|
88
57
|
# --------------------------- Resampling and time shifting functions -------------------------------------------
|
|
89
|
-
|
|
90
|
-
class ConvolutionGridder:
|
|
91
|
-
def __init__(self, timeaxis, width, method='gauss', circular=True, upsampleratio=100, doplot=False, debug=False):
|
|
92
|
-
self.upsampleratio = upsampleratio
|
|
93
|
-
self.initstep = timeaxis[1] - timeaxis[0]
|
|
94
|
-
self.initstart = timeaxis[0]
|
|
95
|
-
self.initend = timeaxis[-1]
|
|
96
|
-
self.hiresstep = self.initstep / np.float64(self.upsampleratio)
|
|
97
|
-
if method == 'gauss':
|
|
98
|
-
fullwidth = 2.355 * width
|
|
99
|
-
fullwidthpts = int(np.round(fullwidth / self.hiresstep, 0))
|
|
100
|
-
fullwidthpts += ((fullwidthpts % 2) - 1)
|
|
101
|
-
self.hires_x = np.linspace(-fullwidth / 2.0, fullwidth / 2.0, numpts = fullwidthpts, endpoint=True)
|
|
102
|
-
if method == 'gauss':
|
|
103
|
-
self.hires_y = tide_fit.gauss_eval(self.hires_x, np.array([1.0, 0.0, width])
|
|
104
|
-
if debug:
|
|
105
|
-
print(self.hires_x)
|
|
106
|
-
if doplot:
|
|
107
|
-
fig = pl.figure()
|
|
108
|
-
ax = fig.add_subplot(111)
|
|
109
|
-
ax.set_title('congrid convolution function')
|
|
110
|
-
pl.plot(self.hires_x, self.hires_y)
|
|
111
|
-
pl.legend(('input', 'hires'))
|
|
112
|
-
pl.show()
|
|
113
|
-
|
|
114
|
-
def gridded(xvals, yvals):
|
|
115
|
-
if len(xvals) != len(yvals):
|
|
116
|
-
print('x and y vectors do not match - aborting')
|
|
117
|
-
return None
|
|
118
|
-
for i in range(len(xvals)):
|
|
119
|
-
outindices = ((newtimeaxis - self.hiresstart) // self.hiresstep).astype(int)
|
|
120
|
-
"""
|
|
121
|
-
|
|
122
|
-
congridyvals = {}
|
|
58
|
+
congridyvals: dict = {}
|
|
123
59
|
congridyvals["kernel"] = "kaiser"
|
|
124
60
|
congridyvals["width"] = 3.0
|
|
125
61
|
|
|
126
62
|
|
|
127
63
|
def congrid(
|
|
128
|
-
xaxis,
|
|
129
|
-
loc,
|
|
130
|
-
val,
|
|
131
|
-
width,
|
|
132
|
-
kernel="kaiser",
|
|
133
|
-
cache=True,
|
|
134
|
-
cyclic=True,
|
|
135
|
-
debug=False,
|
|
136
|
-
onlykeynotices=True,
|
|
137
|
-
):
|
|
64
|
+
xaxis: NDArray[np.floating[Any]],
|
|
65
|
+
loc: float,
|
|
66
|
+
val: float,
|
|
67
|
+
width: float,
|
|
68
|
+
kernel: str = "kaiser",
|
|
69
|
+
cache: bool = True,
|
|
70
|
+
cyclic: bool = True,
|
|
71
|
+
debug: bool = False,
|
|
72
|
+
onlykeynotices: bool = True,
|
|
73
|
+
) -> Tuple[NDArray[np.floating[Any]], NDArray[np.floating[Any]], NDArray[np.floating[Any]]]:
|
|
138
74
|
"""
|
|
139
|
-
Perform a convolution gridding operation with a Kaiser-Bessel or Gaussian kernel
|
|
140
|
-
|
|
75
|
+
Perform a convolution gridding operation with a Kaiser-Bessel or Gaussian kernel.
|
|
76
|
+
|
|
77
|
+
This function convolves a given value with a specified gridding kernel and projects
|
|
78
|
+
the result onto a target axis. It supports both cyclic and non-cyclic boundary
|
|
79
|
+
conditions and caches kernel values for performance optimization.
|
|
141
80
|
|
|
142
81
|
Parameters
|
|
143
82
|
----------
|
|
144
|
-
xaxis:
|
|
145
|
-
The target axis for resampling
|
|
146
|
-
loc: float
|
|
147
|
-
The location, in x-axis units, of the sample to be gridded
|
|
148
|
-
val: float
|
|
149
|
-
The value to be gridded
|
|
150
|
-
width: float
|
|
151
|
-
The width of the gridding kernel in target bins
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
83
|
+
xaxis : NDArray[np.floating[Any]]
|
|
84
|
+
The target axis for resampling. Should be a 1D array of evenly spaced points.
|
|
85
|
+
loc : float
|
|
86
|
+
The location, in x-axis units, of the sample to be gridded.
|
|
87
|
+
val : float
|
|
88
|
+
The value to be gridded.
|
|
89
|
+
width : float
|
|
90
|
+
The width of the gridding kernel in target bins. Must be a half-integral value
|
|
91
|
+
between 1.5 and 5.0 inclusive.
|
|
92
|
+
kernel : {'old', 'gauss', 'kaiser'}, optional
|
|
93
|
+
The type of convolution gridding kernel. Default is 'kaiser'.
|
|
94
|
+
- 'old': Uses a Gaussian kernel with fixed width.
|
|
95
|
+
- 'gauss': Uses a Gaussian kernel with optimized sigma.
|
|
96
|
+
- 'kaiser': Uses a Kaiser-Bessel kernel with optimized beta.
|
|
97
|
+
cache : bool, optional
|
|
98
|
+
If True, caches kernel values for performance. Default is True.
|
|
99
|
+
cyclic : bool, optional
|
|
100
|
+
When True, gridding wraps around the endpoints of xaxis. Default is True.
|
|
101
|
+
debug : bool, optional
|
|
102
|
+
When True, outputs additional information about the gridding process.
|
|
103
|
+
Default is False.
|
|
104
|
+
onlykeynotices : bool, optional
|
|
105
|
+
When True, suppresses certain debug messages. Default is True.
|
|
158
106
|
|
|
159
107
|
Returns
|
|
160
108
|
-------
|
|
161
|
-
vals:
|
|
162
|
-
The input value, convolved with the gridding kernel, projected
|
|
163
|
-
weights:
|
|
164
|
-
The values of convolution kernel, projected
|
|
165
|
-
indices:
|
|
166
|
-
The indices along the x
|
|
109
|
+
vals : NDArray[np.floating[Any]]
|
|
110
|
+
The input value, convolved with the gridding kernel, projected onto x-axis points.
|
|
111
|
+
weights : NDArray[np.floating[Any]]
|
|
112
|
+
The values of the convolution kernel, projected onto x-axis points (used for normalization).
|
|
113
|
+
indices : NDArray[int[Any]]
|
|
114
|
+
The indices along the x-axis where the vals and weights fall.
|
|
167
115
|
|
|
168
116
|
Notes
|
|
169
117
|
-----
|
|
170
|
-
|
|
171
|
-
|
|
118
|
+
This implementation is based on the method described in:
|
|
119
|
+
IEEE TRANSACTIONS ON MEDICAL IMAGING. VOL. 10, NO. 3, SEPTEMBER 1991
|
|
120
|
+
|
|
121
|
+
Examples
|
|
122
|
+
--------
|
|
123
|
+
>>> import numpy as np
|
|
124
|
+
>>> xaxis = np.linspace(0, 10, 100)
|
|
125
|
+
>>> vals, weights, indices = congrid(xaxis, 5.5, 1.0, 2.0)
|
|
126
|
+
>>> print(vals.shape)
|
|
127
|
+
(100,)
|
|
172
128
|
"""
|
|
173
129
|
global congridyvals
|
|
174
130
|
|
|
@@ -247,7 +203,7 @@ def congrid(
|
|
|
247
203
|
offsetinpts = center + offset
|
|
248
204
|
startpt = int(np.ceil(offsetinpts - width / 2.0))
|
|
249
205
|
endpt = int(np.floor(offsetinpts + width / 2.0))
|
|
250
|
-
indices = np.remainder(range(startpt, endpt + 1), len(xaxis))
|
|
206
|
+
indices = np.remainder(np.array(list(range(startpt, endpt + 1))), len(xaxis))
|
|
251
207
|
try:
|
|
252
208
|
yvals = congridyvals[offsetkey]
|
|
253
209
|
except KeyError:
|
|
@@ -283,6 +239,53 @@ class FastResampler:
|
|
|
283
239
|
debug=False,
|
|
284
240
|
method="univariate",
|
|
285
241
|
):
|
|
242
|
+
"""
|
|
243
|
+
Initialize the FastResampler with given time axis and time course data.
|
|
244
|
+
|
|
245
|
+
This constructor prepares high-resolution time series data by resampling the input
|
|
246
|
+
time course using one of several methods, with optional padding and plotting.
|
|
247
|
+
|
|
248
|
+
Parameters
|
|
249
|
+
----------
|
|
250
|
+
timeaxis : array-like
|
|
251
|
+
The time axis of the input data. Should be a 1D array of time points.
|
|
252
|
+
timecourse : array-like
|
|
253
|
+
The time course data corresponding to `timeaxis`. Should be a 1D array of values.
|
|
254
|
+
padtime : float, optional
|
|
255
|
+
Padding time in seconds to extend the resampled time axis on both ends.
|
|
256
|
+
Default is 30.0.
|
|
257
|
+
upsampleratio : int, optional
|
|
258
|
+
The upsampling ratio used for resampling. Default is 100.
|
|
259
|
+
doplot : bool, optional
|
|
260
|
+
If True, plot the original and high-resolution time courses. Default is False.
|
|
261
|
+
debug : bool, optional
|
|
262
|
+
If True, print debug information during initialization. Default is False.
|
|
263
|
+
method : str, optional
|
|
264
|
+
Resampling method to use. Options are:
|
|
265
|
+
- "univariate": Uses custom resampling logic.
|
|
266
|
+
- "poly": Uses `scipy.signal.resample_poly`.
|
|
267
|
+
- "fourier": Uses `scipy.signal.resample`.
|
|
268
|
+
Default is "univariate".
|
|
269
|
+
|
|
270
|
+
Returns
|
|
271
|
+
-------
|
|
272
|
+
None
|
|
273
|
+
This method initializes instance attributes and does not return a value.
|
|
274
|
+
|
|
275
|
+
Notes
|
|
276
|
+
-----
|
|
277
|
+
The resampled time axis (`hires_x`) is generated by extending the original time axis
|
|
278
|
+
by `padtime` on each side, using a step size that is `1 / upsampleratio` of the
|
|
279
|
+
original step size. The `hires_y` array contains the resampled time course values.
|
|
280
|
+
|
|
281
|
+
Examples
|
|
282
|
+
--------
|
|
283
|
+
>>> import numpy as np
|
|
284
|
+
>>> from scipy import signal
|
|
285
|
+
>>> timeaxis = np.linspace(0, 10, 100)
|
|
286
|
+
>>> timecourse = np.sin(timeaxis)
|
|
287
|
+
>>> resampler = FastResampler(timeaxis, timecourse, padtime=5.0, method="poly")
|
|
288
|
+
"""
|
|
286
289
|
self.timeaxis = timeaxis
|
|
287
290
|
self.timecourse = timecourse
|
|
288
291
|
self.upsampleratio = upsampleratio
|
|
@@ -331,17 +334,98 @@ class FastResampler:
|
|
|
331
334
|
if doplot:
|
|
332
335
|
import matplolib.pyplot as pl
|
|
333
336
|
|
|
334
|
-
fig =
|
|
337
|
+
fig = plt.figure()
|
|
335
338
|
ax = fig.add_subplot(111)
|
|
336
339
|
ax.set_title("FastResampler initial timecourses")
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
+
plt.plot(timeaxis, timecourse, self.hires_x, self.hires_y)
|
|
341
|
+
plt.legend(("input", "hires"))
|
|
342
|
+
plt.show()
|
|
340
343
|
|
|
341
344
|
def getdata(self):
|
|
345
|
+
"""
|
|
346
|
+
Retrieve time series data and related parameters.
|
|
347
|
+
|
|
348
|
+
Returns
|
|
349
|
+
-------
|
|
350
|
+
tuple
|
|
351
|
+
A tuple containing:
|
|
352
|
+
- timeaxis : array_like
|
|
353
|
+
Time axis values
|
|
354
|
+
- timecourse : array_like
|
|
355
|
+
Time course data values
|
|
356
|
+
- hires_x : array_like
|
|
357
|
+
High resolution x-axis data
|
|
358
|
+
- hires_y : array_like
|
|
359
|
+
High resolution y-axis data
|
|
360
|
+
- inverse_initstep : float
|
|
361
|
+
Reciprocal of the initial step size (1.0 / self.initstep)
|
|
362
|
+
|
|
363
|
+
Notes
|
|
364
|
+
-----
|
|
365
|
+
This function provides access to all time series data and associated
|
|
366
|
+
high resolution parameters stored in the object instance. The returned
|
|
367
|
+
inverse_initstep value is commonly used for normalization or scaling
|
|
368
|
+
operations in time series analysis.
|
|
369
|
+
|
|
370
|
+
Examples
|
|
371
|
+
--------
|
|
372
|
+
>>> data = obj.getdata()
|
|
373
|
+
>>> time_axis, time_course, hires_x, hires_y, inv_step = data
|
|
374
|
+
>>> print(f"Time course shape: {time_course.shape}")
|
|
375
|
+
"""
|
|
342
376
|
return self.timeaxis, self.timecourse, self.hires_x, self.hires_y, 1.0 / self.initstep
|
|
343
377
|
|
|
344
378
|
def info(self, prefix=""):
|
|
379
|
+
"""
|
|
380
|
+
Print information about the object's time and sampling parameters.
|
|
381
|
+
|
|
382
|
+
This method displays various time-related attributes and sampling parameters
|
|
383
|
+
of the object, with optional prefix for better formatting in output.
|
|
384
|
+
|
|
385
|
+
Parameters
|
|
386
|
+
----------
|
|
387
|
+
prefix : str, optional
|
|
388
|
+
String to prepend to each printed line, useful for indentation or
|
|
389
|
+
grouping related output. Default is empty string.
|
|
390
|
+
|
|
391
|
+
Returns
|
|
392
|
+
-------
|
|
393
|
+
None
|
|
394
|
+
This method prints information to stdout and does not return any value.
|
|
395
|
+
|
|
396
|
+
Notes
|
|
397
|
+
-----
|
|
398
|
+
The method prints the following attributes:
|
|
399
|
+
- timeaxis: Time axis values
|
|
400
|
+
- timecourse: Time course data
|
|
401
|
+
- upsampleratio: Upsampling ratio
|
|
402
|
+
- padtime: Padding time
|
|
403
|
+
- initstep: Initial step size
|
|
404
|
+
- initstart: Initial start time
|
|
405
|
+
- initend: Initial end time
|
|
406
|
+
- hiresstep: High-resolution step size
|
|
407
|
+
- hires_x[0]: First value of high-resolution x-axis
|
|
408
|
+
- hires_x[-1]: Last value of high-resolution x-axis
|
|
409
|
+
- hiresstart: High-resolution start time
|
|
410
|
+
- hiresend: High-resolution end time
|
|
411
|
+
- method: Interpolation/processing method used
|
|
412
|
+
- hires_y[0]: First value of high-resolution y-axis
|
|
413
|
+
- hires_y[-1]: Last value of high-resolution y-axis
|
|
414
|
+
|
|
415
|
+
Examples
|
|
416
|
+
--------
|
|
417
|
+
>>> obj.info()
|
|
418
|
+
timeaxis=100
|
|
419
|
+
timecourse=200
|
|
420
|
+
upsampleratio=4
|
|
421
|
+
...
|
|
422
|
+
|
|
423
|
+
>>> obj.info(prefix=" ")
|
|
424
|
+
timeaxis=100
|
|
425
|
+
timecourse=200
|
|
426
|
+
upsampleratio=4
|
|
427
|
+
...
|
|
428
|
+
"""
|
|
345
429
|
print(f"{prefix}{self.timeaxis=}")
|
|
346
430
|
print(f"{prefix}{self.timecourse=}")
|
|
347
431
|
print(f"{prefix}{self.upsampleratio=}")
|
|
@@ -359,6 +443,35 @@ class FastResampler:
|
|
|
359
443
|
print(f"{prefix}{self.hires_y[-1]=}")
|
|
360
444
|
|
|
361
445
|
def save(self, outputname):
|
|
446
|
+
"""
|
|
447
|
+
Save the timecourse data to a TSV file.
|
|
448
|
+
|
|
449
|
+
This method writes the internal timecourse data to a tab-separated values file
|
|
450
|
+
with additional metadata in the header. The output includes the timecourse data
|
|
451
|
+
along with timing information derived from the object's initialization parameters.
|
|
452
|
+
|
|
453
|
+
Parameters
|
|
454
|
+
----------
|
|
455
|
+
outputname : str
|
|
456
|
+
The path and filename where the TSV output will be saved.
|
|
457
|
+
|
|
458
|
+
Returns
|
|
459
|
+
-------
|
|
460
|
+
None
|
|
461
|
+
This method does not return any value.
|
|
462
|
+
|
|
463
|
+
Notes
|
|
464
|
+
-----
|
|
465
|
+
The method uses the `tide_io.writebidstsv` function to perform the actual file writing.
|
|
466
|
+
The time step is calculated as 1.0 divided by `self.initstep`, and the start time
|
|
467
|
+
is taken from `self.initstart`. The output file includes a header with description
|
|
468
|
+
metadata indicating this is a lagged timecourse generator.
|
|
469
|
+
|
|
470
|
+
Examples
|
|
471
|
+
--------
|
|
472
|
+
>>> obj.save("output_timecourse.tsv")
|
|
473
|
+
>>> # Creates a TSV file with the timecourse data and metadata
|
|
474
|
+
"""
|
|
362
475
|
tide_io.writebidstsv(
|
|
363
476
|
outputname,
|
|
364
477
|
self.timecourse,
|
|
@@ -370,6 +483,41 @@ class FastResampler:
|
|
|
370
483
|
)
|
|
371
484
|
|
|
372
485
|
def yfromx(self, newtimeaxis, doplot=False, debug=False):
|
|
486
|
+
"""
|
|
487
|
+
Resample y-values from a high-resolution time axis to a new time axis.
|
|
488
|
+
|
|
489
|
+
This method maps values from a high-resolution y-array (`self.hires_y`) to a
|
|
490
|
+
new time axis (`newtimeaxis`) by linear interpolation based on the step size
|
|
491
|
+
and start of the high-resolution axis.
|
|
492
|
+
|
|
493
|
+
Parameters
|
|
494
|
+
----------
|
|
495
|
+
newtimeaxis : array-like
|
|
496
|
+
The new time axis to which the y-values will be resampled.
|
|
497
|
+
doplot : bool, optional
|
|
498
|
+
If True, plot the original high-resolution y-values and the resampled
|
|
499
|
+
values for comparison. Default is False.
|
|
500
|
+
debug : bool, optional
|
|
501
|
+
If True, print debug information including internal parameters and
|
|
502
|
+
bounds checking. Default is False.
|
|
503
|
+
|
|
504
|
+
Returns
|
|
505
|
+
-------
|
|
506
|
+
out_y : ndarray
|
|
507
|
+
The resampled y-values corresponding to `newtimeaxis`.
|
|
508
|
+
|
|
509
|
+
Notes
|
|
510
|
+
-----
|
|
511
|
+
This function assumes that `self.hires_y` has been precomputed and that
|
|
512
|
+
the internal parameters (`self.hiresstart`, `self.hiresstep`) are valid.
|
|
513
|
+
An IndexError is raised if any index in `outindices` is out of bounds.
|
|
514
|
+
|
|
515
|
+
Examples
|
|
516
|
+
--------
|
|
517
|
+
>>> resampler = FastResampler()
|
|
518
|
+
>>> new_times = np.linspace(0, 10, 100)
|
|
519
|
+
>>> y_vals = resampler.yfromx(new_times, doplot=True)
|
|
520
|
+
"""
|
|
373
521
|
if debug:
|
|
374
522
|
print("FastResampler: yfromx called with following parameters")
|
|
375
523
|
print(" padtime:, ", self.padtime)
|
|
@@ -392,16 +540,59 @@ class FastResampler:
|
|
|
392
540
|
print(" requested axis limits:", newtimeaxis[0], newtimeaxis[-1])
|
|
393
541
|
sys.exit()
|
|
394
542
|
if doplot:
|
|
395
|
-
fig =
|
|
543
|
+
fig = plt.figure()
|
|
396
544
|
ax = fig.add_subplot(111)
|
|
397
545
|
ax.set_title("FastResampler timecourses")
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
546
|
+
plt.plot(self.hires_x, self.hires_y, newtimeaxis, out_y)
|
|
547
|
+
plt.legend(("hires", "output"))
|
|
548
|
+
plt.show()
|
|
401
549
|
return out_y
|
|
402
550
|
|
|
403
551
|
|
|
404
|
-
def FastResamplerFromFile(
|
|
552
|
+
def FastResamplerFromFile(
|
|
553
|
+
inputname: str, colspec: Optional[str] = None, debug: bool = False, **kwargs
|
|
554
|
+
) -> FastResampler:
|
|
555
|
+
"""
|
|
556
|
+
Create a FastResampler from a BIDS TSV file.
|
|
557
|
+
|
|
558
|
+
This function reads data from a BIDS TSV file and creates a FastResampler object
|
|
559
|
+
for efficient time series resampling operations. The input file must contain
|
|
560
|
+
exactly one column of data.
|
|
561
|
+
|
|
562
|
+
Parameters
|
|
563
|
+
----------
|
|
564
|
+
inputname : str
|
|
565
|
+
Path to the input BIDS TSV file containing the time series data
|
|
566
|
+
colspec : str, optional
|
|
567
|
+
Column specification for selecting specific columns from the TSV file.
|
|
568
|
+
If None, all columns are read (default: None)
|
|
569
|
+
debug : bool, optional
|
|
570
|
+
Enable debug output printing (default: False)
|
|
571
|
+
**kwargs
|
|
572
|
+
Additional keyword arguments passed to the FastResampler constructor
|
|
573
|
+
|
|
574
|
+
Returns
|
|
575
|
+
-------
|
|
576
|
+
FastResampler
|
|
577
|
+
A FastResampler object initialized with the time axis and data from the input file
|
|
578
|
+
|
|
579
|
+
Raises
|
|
580
|
+
------
|
|
581
|
+
ValueError
|
|
582
|
+
If the input file contains multiple columns of data
|
|
583
|
+
|
|
584
|
+
Notes
|
|
585
|
+
-----
|
|
586
|
+
The function internally calls `tide_io.readbidstsv` to read the input file and
|
|
587
|
+
constructs a time axis using `np.linspace` based on the sampling rate and
|
|
588
|
+
start time from the input file.
|
|
589
|
+
|
|
590
|
+
Examples
|
|
591
|
+
--------
|
|
592
|
+
>>> resampler = FastResamplerFromFile('data.tsv')
|
|
593
|
+
>>> resampler = FastResamplerFromFile('data.tsv', colspec='column1')
|
|
594
|
+
>>> resampler = FastResamplerFromFile('data.tsv', debug=True)
|
|
595
|
+
"""
|
|
405
596
|
(
|
|
406
597
|
insamplerate,
|
|
407
598
|
instarttime,
|
|
@@ -425,29 +616,65 @@ def FastResamplerFromFile(inputname, colspec=None, debug=False, **kwargs):
|
|
|
425
616
|
|
|
426
617
|
|
|
427
618
|
def doresample(
|
|
428
|
-
orig_x,
|
|
429
|
-
orig_y,
|
|
430
|
-
new_x,
|
|
431
|
-
method="cubic",
|
|
432
|
-
padlen=0,
|
|
433
|
-
padtype="reflect",
|
|
434
|
-
antialias=False,
|
|
435
|
-
debug=False,
|
|
436
|
-
):
|
|
619
|
+
orig_x: ArrayLike,
|
|
620
|
+
orig_y: ArrayLike,
|
|
621
|
+
new_x: ArrayLike,
|
|
622
|
+
method: str = "cubic",
|
|
623
|
+
padlen: int = 0,
|
|
624
|
+
padtype: str = "reflect",
|
|
625
|
+
antialias: bool = False,
|
|
626
|
+
debug: bool = False,
|
|
627
|
+
) -> NDArray:
|
|
437
628
|
"""
|
|
438
|
-
Resample data from one spacing to another.
|
|
629
|
+
Resample data from one spacing to another.
|
|
630
|
+
|
|
631
|
+
By default, does not apply any antialiasing filter.
|
|
439
632
|
|
|
440
633
|
Parameters
|
|
441
634
|
----------
|
|
442
|
-
orig_x
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
635
|
+
orig_x : array-like
|
|
636
|
+
Original x-coordinates of the data to be resampled.
|
|
637
|
+
orig_y : array-like
|
|
638
|
+
Original y-values corresponding to `orig_x`.
|
|
639
|
+
new_x : array-like
|
|
640
|
+
New x-coordinates at which to evaluate the resampled data.
|
|
641
|
+
method : str, optional
|
|
642
|
+
Interpolation method to use. Options are:
|
|
643
|
+
- "cubic": cubic spline interpolation (default)
|
|
644
|
+
- "quadratic": quadratic spline interpolation
|
|
645
|
+
- "univariate": univariate spline interpolation using `scipy.interpolate.UnivariateSpline`
|
|
646
|
+
padlen : int, optional
|
|
647
|
+
Number of elements to pad the input data at both ends. Default is 0.
|
|
648
|
+
padtype : str, optional
|
|
649
|
+
Type of padding to use when `padlen > 0`. Default is "reflect".
|
|
650
|
+
Passed to `tide_filt.padvec`.
|
|
651
|
+
antialias : bool, optional
|
|
652
|
+
If True, apply an antialiasing filter before resampling if the original
|
|
653
|
+
sampling frequency is higher than the target frequency. Default is False.
|
|
654
|
+
debug : bool, optional
|
|
655
|
+
If True, print debug information and display a plot of the original and
|
|
656
|
+
padded data. Default is False.
|
|
447
657
|
|
|
448
658
|
Returns
|
|
449
659
|
-------
|
|
660
|
+
ndarray
|
|
661
|
+
Resampled y-values at coordinates specified by `new_x`. If an invalid
|
|
662
|
+
interpolation method is specified, returns None.
|
|
450
663
|
|
|
664
|
+
Notes
|
|
665
|
+
-----
|
|
666
|
+
- The function uses padding to handle edge effects during interpolation.
|
|
667
|
+
- When `antialias=True`, a non-causal filter is applied to reduce aliasing
|
|
668
|
+
artifacts when downsampling.
|
|
669
|
+
- The `tide_filt` module is used for padding and filtering operations.
|
|
670
|
+
|
|
671
|
+
Examples
|
|
672
|
+
--------
|
|
673
|
+
>>> import numpy as np
|
|
674
|
+
>>> x = np.linspace(0, 10, 100)
|
|
675
|
+
>>> y = np.sin(x)
|
|
676
|
+
>>> new_x = np.linspace(0, 10, 200)
|
|
677
|
+
>>> y_resampled = doresample(x, y, new_x, method="cubic")
|
|
451
678
|
"""
|
|
452
679
|
tstep = orig_x[1] - orig_x[0]
|
|
453
680
|
if padlen > 0:
|
|
@@ -466,11 +693,11 @@ def doresample(
|
|
|
466
693
|
print("lens:", len(pad_x), len(pad_y))
|
|
467
694
|
print(pad_x)
|
|
468
695
|
print(pad_y)
|
|
469
|
-
fig =
|
|
696
|
+
fig = plt.figure()
|
|
470
697
|
ax = fig.add_subplot(111)
|
|
471
698
|
ax.set_title("Original and padded vector")
|
|
472
|
-
|
|
473
|
-
|
|
699
|
+
plt.plot(orig_x, orig_y + 1.0, pad_x, pad_y)
|
|
700
|
+
plt.show()
|
|
474
701
|
|
|
475
702
|
# antialias and ringstop filter
|
|
476
703
|
init_freq = len(pad_x) / (pad_x[-1] - pad_x[0])
|
|
@@ -501,31 +728,75 @@ def doresample(
|
|
|
501
728
|
|
|
502
729
|
|
|
503
730
|
def arbresample(
|
|
504
|
-
inputdata,
|
|
505
|
-
init_freq,
|
|
506
|
-
final_freq,
|
|
507
|
-
intermed_freq=0.0,
|
|
508
|
-
method="univariate",
|
|
509
|
-
antialias=True,
|
|
510
|
-
decimate=False,
|
|
511
|
-
debug=False,
|
|
512
|
-
):
|
|
731
|
+
inputdata: ArrayLike,
|
|
732
|
+
init_freq: float,
|
|
733
|
+
final_freq: float,
|
|
734
|
+
intermed_freq: float = 0.0,
|
|
735
|
+
method: str = "univariate",
|
|
736
|
+
antialias: bool = True,
|
|
737
|
+
decimate: bool = False,
|
|
738
|
+
debug: bool = False,
|
|
739
|
+
) -> NDArray:
|
|
513
740
|
"""
|
|
741
|
+
Resample input data from an initial frequency to a final frequency using either
|
|
742
|
+
direct resampling or a two-step process with intermediate frequency.
|
|
743
|
+
|
|
744
|
+
This function supports both upsampling and downsampling, with optional anti-aliasing
|
|
745
|
+
and decimation. It can operate in debug mode to print intermediate steps and
|
|
746
|
+
statistics.
|
|
514
747
|
|
|
515
748
|
Parameters
|
|
516
749
|
----------
|
|
517
|
-
inputdata
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
750
|
+
inputdata : ArrayLike
|
|
751
|
+
Input signal or data to be resampled. Should be a 1-D array-like object.
|
|
752
|
+
init_freq : float
|
|
753
|
+
Initial sampling frequency of the input data in Hz.
|
|
754
|
+
final_freq : float
|
|
755
|
+
Target sampling frequency of the output data in Hz.
|
|
756
|
+
intermed_freq : float, optional
|
|
757
|
+
Intermediate sampling frequency used in the two-step resampling process.
|
|
758
|
+
If not specified (default: 0.0), it is automatically set to the maximum of
|
|
759
|
+
2 * init_freq and 2 * final_freq.
|
|
760
|
+
method : str, optional
|
|
761
|
+
Interpolation method to use for resampling. Default is "univariate".
|
|
762
|
+
Other options may be supported depending on the underlying implementation.
|
|
763
|
+
antialias : bool, optional
|
|
764
|
+
If True (default), apply anti-aliasing filter during downsampling using
|
|
765
|
+
`scipy.signal.decimate`. If False, use simple interpolation for downsampling.
|
|
766
|
+
decimate : bool, optional
|
|
767
|
+
If True, perform upsampling followed by decimation for downsampling.
|
|
768
|
+
If False, use a two-step resampling approach with `dotwostepresample`.
|
|
769
|
+
Default is False.
|
|
770
|
+
debug : bool, optional
|
|
771
|
+
If True, print debug information including number of points before and after
|
|
772
|
+
resampling, and intermediate steps. Default is False.
|
|
525
773
|
|
|
526
774
|
Returns
|
|
527
775
|
-------
|
|
776
|
+
NDArray
|
|
777
|
+
Resampled data as a NumPy array with length adjusted according to `final_freq`.
|
|
528
778
|
|
|
779
|
+
Notes
|
|
780
|
+
-----
|
|
781
|
+
- When `decimate=True`, the function uses integer decimation for efficient downsampling.
|
|
782
|
+
- For downsampling, if `antialias=False`, the function uses linear interpolation
|
|
783
|
+
instead of filtering to reduce computational cost.
|
|
784
|
+
- The `intermed_freq` is automatically calculated when `decimate=True` and
|
|
785
|
+
`final_freq < init_freq`.
|
|
786
|
+
|
|
787
|
+
Examples
|
|
788
|
+
--------
|
|
789
|
+
>>> import numpy as np
|
|
790
|
+
>>> data = np.random.rand(100)
|
|
791
|
+
>>> resampled = arbresample(data, init_freq=100, final_freq=50, decimate=True)
|
|
792
|
+
>>> print(len(resampled))
|
|
793
|
+
50
|
|
794
|
+
|
|
795
|
+
See Also
|
|
796
|
+
--------
|
|
797
|
+
upsample : Function used for upsampling when `decimate=True`.
|
|
798
|
+
dotwostepresample : Function used for two-step resampling when `decimate=False`.
|
|
799
|
+
scipy.signal.decimate : Anti-aliasing filter used when `antialias=True`.
|
|
529
800
|
"""
|
|
530
801
|
if debug:
|
|
531
802
|
print("arbresample - initial points:", len(inputdata))
|
|
@@ -597,7 +868,62 @@ def arbresample(
|
|
|
597
868
|
return resampled
|
|
598
869
|
|
|
599
870
|
|
|
600
|
-
def upsample(
|
|
871
|
+
def upsample(
|
|
872
|
+
inputdata: ArrayLike,
|
|
873
|
+
Fs_init: float,
|
|
874
|
+
Fs_higher: float,
|
|
875
|
+
method: str = "univariate",
|
|
876
|
+
intfac: bool = False,
|
|
877
|
+
dofilt: bool = True,
|
|
878
|
+
debug: bool = False,
|
|
879
|
+
) -> NDArray:
|
|
880
|
+
"""
|
|
881
|
+
Upsample input data to a higher sampling frequency.
|
|
882
|
+
|
|
883
|
+
This function increases the sampling rate of the input data using interpolation
|
|
884
|
+
and optional filtering. It supports different interpolation methods and allows
|
|
885
|
+
for control over the resampling factor and filtering behavior.
|
|
886
|
+
|
|
887
|
+
Parameters
|
|
888
|
+
----------
|
|
889
|
+
inputdata : ArrayLike
|
|
890
|
+
Input time series data to be upsampled.
|
|
891
|
+
Fs_init : float
|
|
892
|
+
Initial sampling frequency of the input data (Hz).
|
|
893
|
+
Fs_higher : float
|
|
894
|
+
Target sampling frequency to upsample to (Hz). Must be greater than `Fs_init`.
|
|
895
|
+
method : str, optional
|
|
896
|
+
Interpolation method to use. Default is "univariate". Other options depend
|
|
897
|
+
on the implementation of `doresample`.
|
|
898
|
+
intfac : bool, optional
|
|
899
|
+
If True, use integer resampling factor based on `Fs_higher // Fs_init`.
|
|
900
|
+
If False, compute resampled points based on time duration. Default is False.
|
|
901
|
+
dofilt : bool, optional
|
|
902
|
+
If True, apply a non-causal filter to prevent aliasing. Default is True.
|
|
903
|
+
debug : bool, optional
|
|
904
|
+
If True, print timing information. Default is False.
|
|
905
|
+
|
|
906
|
+
Returns
|
|
907
|
+
-------
|
|
908
|
+
NDArray
|
|
909
|
+
Upsampled time series data with the new sampling frequency.
|
|
910
|
+
|
|
911
|
+
Notes
|
|
912
|
+
-----
|
|
913
|
+
- The function uses linear interpolation by default, but the actual method
|
|
914
|
+
depends on the `doresample` function implementation.
|
|
915
|
+
- If `dofilt` is True, a trapezoidal non-causal filter is applied with a
|
|
916
|
+
stop frequency set to the minimum of 1.1 * Fs_init / 2.0 and Fs_higher / 2.0.
|
|
917
|
+
- The function will terminate if `Fs_higher` is not greater than `Fs_init`.
|
|
918
|
+
|
|
919
|
+
Examples
|
|
920
|
+
--------
|
|
921
|
+
>>> import numpy as np
|
|
922
|
+
>>> data = np.sin(np.linspace(0, 4*np.pi, 100))
|
|
923
|
+
>>> upsampled = upsample(data, Fs_init=10.0, Fs_higher=20.0)
|
|
924
|
+
>>> print(len(upsampled))
|
|
925
|
+
200
|
|
926
|
+
"""
|
|
601
927
|
starttime = time.time()
|
|
602
928
|
if Fs_higher <= Fs_init:
|
|
603
929
|
print("upsample: target frequency must be higher than initial frequency")
|
|
@@ -626,29 +952,60 @@ def upsample(inputdata, Fs_init, Fs_higher, method="univariate", intfac=False, d
|
|
|
626
952
|
|
|
627
953
|
|
|
628
954
|
def dotwostepresample(
|
|
629
|
-
orig_x,
|
|
630
|
-
orig_y,
|
|
631
|
-
intermed_freq,
|
|
632
|
-
final_freq,
|
|
633
|
-
method="univariate",
|
|
634
|
-
antialias=True,
|
|
635
|
-
debug=False,
|
|
636
|
-
):
|
|
955
|
+
orig_x: ArrayLike,
|
|
956
|
+
orig_y: ArrayLike,
|
|
957
|
+
intermed_freq: float,
|
|
958
|
+
final_freq: float,
|
|
959
|
+
method: str = "univariate",
|
|
960
|
+
antialias: bool = True,
|
|
961
|
+
debug: bool = False,
|
|
962
|
+
) -> NDArray:
|
|
637
963
|
"""
|
|
964
|
+
Resample a signal from original frequency to final frequency using a two-step process:
|
|
965
|
+
first upsampling to an intermediate frequency, then downsampling to the final frequency.
|
|
966
|
+
|
|
967
|
+
This function performs resampling by first interpolating the input signal to an
|
|
968
|
+
intermediate frequency that is higher than the final desired frequency, followed by
|
|
969
|
+
downsampling to the target frequency. Optional antialiasing filtering is applied
|
|
970
|
+
during the upsampling step.
|
|
638
971
|
|
|
639
972
|
Parameters
|
|
640
973
|
----------
|
|
641
|
-
orig_x
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
974
|
+
orig_x : array-like
|
|
975
|
+
Original time axis values (must be monotonically increasing).
|
|
976
|
+
orig_y : array-like
|
|
977
|
+
Original signal values corresponding to `orig_x`.
|
|
978
|
+
intermed_freq : float
|
|
979
|
+
Intermediate frequency to which the signal is upsampled.
|
|
980
|
+
Must be greater than `final_freq`.
|
|
981
|
+
final_freq : float
|
|
982
|
+
Target frequency to which the signal is downsampled.
|
|
983
|
+
method : str, optional
|
|
984
|
+
Interpolation method used for resampling. Default is "univariate".
|
|
985
|
+
Should be compatible with the `doresample` function.
|
|
986
|
+
antialias : bool, optional
|
|
987
|
+
If True, apply an antialiasing filter during upsampling. Default is True.
|
|
988
|
+
debug : bool, optional
|
|
989
|
+
If True, print timing and intermediate information. Default is False.
|
|
647
990
|
|
|
648
991
|
Returns
|
|
649
992
|
-------
|
|
650
|
-
|
|
993
|
+
ndarray
|
|
994
|
+
Resampled signal values at the final frequency.
|
|
651
995
|
|
|
996
|
+
Notes
|
|
997
|
+
-----
|
|
998
|
+
- The intermediate frequency must be strictly greater than the final frequency.
|
|
999
|
+
- The function uses `doresample` for interpolation and `tide_filt.NoncausalFilter`
|
|
1000
|
+
for antialiasing if enabled.
|
|
1001
|
+
- Timing information is printed when `debug=True`.
|
|
1002
|
+
|
|
1003
|
+
Examples
|
|
1004
|
+
--------
|
|
1005
|
+
>>> import numpy as np
|
|
1006
|
+
>>> x = np.linspace(0, 10, 100)
|
|
1007
|
+
>>> y = np.sin(x)
|
|
1008
|
+
>>> resampled = dotwostepresample(x, y, intermed_freq=50.0, final_freq=10.0)
|
|
652
1009
|
"""
|
|
653
1010
|
if intermed_freq <= final_freq:
|
|
654
1011
|
print("intermediate frequency must be higher than final frequency")
|
|
@@ -698,20 +1055,56 @@ def dotwostepresample(
|
|
|
698
1055
|
return resampled_y
|
|
699
1056
|
|
|
700
1057
|
|
|
701
|
-
def calcsliceoffset(
|
|
1058
|
+
def calcsliceoffset(
|
|
1059
|
+
sotype: int, slicenum: int, numslices: int, tr: float, multiband: int = 1
|
|
1060
|
+
) -> float:
|
|
702
1061
|
"""
|
|
1062
|
+
Calculate slice timing offset for slice timing correction.
|
|
1063
|
+
|
|
1064
|
+
This function computes the timing offset (in seconds) for a given slice
|
|
1065
|
+
based on the slice timing correction method specified by `sotype`. The
|
|
1066
|
+
offset is used to align slice acquisition times for functional MRI data
|
|
1067
|
+
preprocessing.
|
|
703
1068
|
|
|
704
1069
|
Parameters
|
|
705
1070
|
----------
|
|
706
|
-
sotype
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
1071
|
+
sotype : int
|
|
1072
|
+
Slice timing correction method:
|
|
1073
|
+
- 0: None
|
|
1074
|
+
- 1: Regular up (0, 1, 2, 3, ...)
|
|
1075
|
+
- 2: Regular down
|
|
1076
|
+
- 3: Use slice order file (not supported)
|
|
1077
|
+
- 4: Use slice timings file (not supported)
|
|
1078
|
+
- 5: Standard interleaved (0, 2, 4, ..., 1, 3, 5, ...)
|
|
1079
|
+
- 6: Siemens interleaved
|
|
1080
|
+
- 7: Siemens multiband interleaved
|
|
1081
|
+
slicenum : int
|
|
1082
|
+
The index of the slice for which to compute the timing offset.
|
|
1083
|
+
numslices : int
|
|
1084
|
+
Total number of slices in the volume.
|
|
1085
|
+
tr : float
|
|
1086
|
+
Repetition time (TR) in seconds.
|
|
1087
|
+
multiband : int, optional
|
|
1088
|
+
Multiband factor (default is 1). Used only for sotype 7 (Siemens
|
|
1089
|
+
multiband interleaved).
|
|
711
1090
|
|
|
712
1091
|
Returns
|
|
713
1092
|
-------
|
|
1093
|
+
float
|
|
1094
|
+
Slice timing offset in seconds.
|
|
714
1095
|
|
|
1096
|
+
Notes
|
|
1097
|
+
-----
|
|
1098
|
+
For sotypes 3 and 4, the function returns 0.0 as these methods are not
|
|
1099
|
+
implemented.
|
|
1100
|
+
|
|
1101
|
+
Examples
|
|
1102
|
+
--------
|
|
1103
|
+
>>> calcsliceoffset(1, 5, 32, 2.0)
|
|
1104
|
+
0.3125
|
|
1105
|
+
|
|
1106
|
+
>>> calcsliceoffset(5, 3, 16, 1.5)
|
|
1107
|
+
0.28125
|
|
715
1108
|
"""
|
|
716
1109
|
# Slice timing correction
|
|
717
1110
|
# 0 : None
|
|
@@ -802,19 +1195,61 @@ def calcsliceoffset(sotype, slicenum, numslices, tr, multiband=1):
|
|
|
802
1195
|
|
|
803
1196
|
# NB: a positive value of shifttrs delays the signal, a negative value advances it
|
|
804
1197
|
# timeshift using fourier phase multiplication
|
|
805
|
-
def timeshift(
|
|
1198
|
+
def timeshift(
|
|
1199
|
+
inputtc: ArrayLike, shifttrs: float, padtrs: int, doplot: bool = False, debug: bool = False
|
|
1200
|
+
) -> Tuple[NDArray, NDArray, NDArray, NDArray]:
|
|
806
1201
|
"""
|
|
1202
|
+
Apply a time shift to a signal using FFT-based modulation and padding.
|
|
1203
|
+
|
|
1204
|
+
This function performs a time shift on an input time course by applying
|
|
1205
|
+
phase modulation in the frequency domain, followed by inverse FFT. It uses
|
|
1206
|
+
padding and reflection to avoid edge discontinuities. The function also
|
|
1207
|
+
returns the corresponding shifted weights and the full padded results.
|
|
807
1208
|
|
|
808
1209
|
Parameters
|
|
809
1210
|
----------
|
|
810
|
-
inputtc
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
1211
|
+
inputtc : array-like
|
|
1212
|
+
Input time course to be shifted. Should be a 1D array of real values.
|
|
1213
|
+
shifttrs : float
|
|
1214
|
+
Time shift in units of samples. Positive values shift the signal forward,
|
|
1215
|
+
negative values shift it backward.
|
|
1216
|
+
padtrs : int
|
|
1217
|
+
Number of samples to pad the input signal on each side before shifting.
|
|
1218
|
+
This helps reduce edge effects.
|
|
1219
|
+
doplot : bool, optional
|
|
1220
|
+
If True, plots the original and shifted signals. Default is False.
|
|
1221
|
+
debug : bool, optional
|
|
1222
|
+
If True, prints debug information during execution. Default is False.
|
|
814
1223
|
|
|
815
1224
|
Returns
|
|
816
1225
|
-------
|
|
1226
|
+
tuple of ndarray
|
|
1227
|
+
A tuple containing:
|
|
1228
|
+
- shifted_y : ndarray
|
|
1229
|
+
The time-shifted signal, cropped to the original length.
|
|
1230
|
+
- shifted_weights : ndarray
|
|
1231
|
+
The corresponding shifted weights, cropped to the original length.
|
|
1232
|
+
- shifted_y_full : ndarray
|
|
1233
|
+
The full time-shifted signal including padding.
|
|
1234
|
+
- shifted_weights_full : ndarray
|
|
1235
|
+
The full shifted weights including padding.
|
|
817
1236
|
|
|
1237
|
+
Notes
|
|
1238
|
+
-----
|
|
1239
|
+
The function uses reflection padding to minimize edge artifacts. The phase
|
|
1240
|
+
modulation is applied in the frequency domain using FFT and inverse FFT.
|
|
1241
|
+
The shift is implemented as a complex exponential modulation.
|
|
1242
|
+
|
|
1243
|
+
Examples
|
|
1244
|
+
--------
|
|
1245
|
+
>>> import numpy as np
|
|
1246
|
+
>>> from scipy import fftpack
|
|
1247
|
+
>>> input_signal = np.sin(np.linspace(0, 4*np.pi, 100))
|
|
1248
|
+
>>> shifted_sig, weights, full_shifted, full_weights = timeshift(
|
|
1249
|
+
... input_signal, shifttrs=5.0, padtrs=10, doplot=False
|
|
1250
|
+
... )
|
|
1251
|
+
>>> print(shifted_sig.shape)
|
|
1252
|
+
(100,)
|
|
818
1253
|
"""
|
|
819
1254
|
# set up useful parameters
|
|
820
1255
|
thelen = np.shape(inputtc)[0]
|
|
@@ -861,17 +1296,17 @@ def timeshift(inputtc, shifttrs, padtrs, doplot=False, debug=False):
|
|
|
861
1296
|
print("thelen:", thelen)
|
|
862
1297
|
print("thepaddedlen:", thepaddedlen)
|
|
863
1298
|
|
|
864
|
-
fig =
|
|
1299
|
+
fig = plt.figure()
|
|
865
1300
|
ax = fig.add_subplot(111)
|
|
866
1301
|
ax.set_title("Initial vector")
|
|
867
|
-
|
|
1302
|
+
plt.plot(xvec, preshifted_y)
|
|
868
1303
|
|
|
869
|
-
fig =
|
|
1304
|
+
fig = plt.figure()
|
|
870
1305
|
ax = fig.add_subplot(111)
|
|
871
1306
|
ax.set_title("Initial and shifted vector")
|
|
872
|
-
|
|
1307
|
+
plt.plot(xvec, preshifted_y, xvec, shifted_y)
|
|
873
1308
|
|
|
874
|
-
|
|
1309
|
+
plt.show()
|
|
875
1310
|
|
|
876
1311
|
return [
|
|
877
1312
|
shifted_y[padtrs : padtrs + thelen],
|
|
@@ -881,16 +1316,67 @@ def timeshift(inputtc, shifttrs, padtrs, doplot=False, debug=False):
|
|
|
881
1316
|
]
|
|
882
1317
|
|
|
883
1318
|
|
|
884
|
-
def timewarp(
|
|
1319
|
+
def timewarp(
|
|
1320
|
+
orig_x: ArrayLike,
|
|
1321
|
+
orig_y: ArrayLike,
|
|
1322
|
+
timeoffset: ArrayLike,
|
|
1323
|
+
demean: bool = True,
|
|
1324
|
+
method: str = "univariate",
|
|
1325
|
+
debug: bool = False,
|
|
1326
|
+
) -> NDArray:
|
|
1327
|
+
"""
|
|
1328
|
+
Apply time warping to align time series data based on time offsets.
|
|
1329
|
+
|
|
1330
|
+
This function performs time warping by resampling input data according to
|
|
1331
|
+
provided time offsets. It can optionally remove the mean of the time offsets
|
|
1332
|
+
before resampling to center the data around zero.
|
|
1333
|
+
|
|
1334
|
+
Parameters
|
|
1335
|
+
----------
|
|
1336
|
+
orig_x : ArrayLike
|
|
1337
|
+
Original time axis values (x-coordinates) for the data to be warped.
|
|
1338
|
+
orig_y : ArrayLike
|
|
1339
|
+
Original signal values (y-coordinates) corresponding to orig_x.
|
|
1340
|
+
timeoffset : ArrayLike
|
|
1341
|
+
Time offsets to be applied to each point in the time axis. Positive values
|
|
1342
|
+
shift data forward in time, negative values shift backward.
|
|
1343
|
+
demean : bool, optional
|
|
1344
|
+
If True, remove the mean of timeoffset before resampling. Default is True.
|
|
1345
|
+
method : str, optional
|
|
1346
|
+
Resampling method to use. Options are 'univariate' or other methods
|
|
1347
|
+
supported by the underlying doresample function. Default is 'univariate'.
|
|
1348
|
+
debug : bool, optional
|
|
1349
|
+
If True, print debugging information about the warping process.
|
|
1350
|
+
Default is False.
|
|
1351
|
+
|
|
1352
|
+
Returns
|
|
1353
|
+
-------
|
|
1354
|
+
NDArray
|
|
1355
|
+
Warped time series data after applying the time offsets and resampling.
|
|
1356
|
+
|
|
1357
|
+
Notes
|
|
1358
|
+
-----
|
|
1359
|
+
The function calculates the maximum deviation in samples and uses half the
|
|
1360
|
+
length of the input data (or 30 seconds worth of samples, whichever is smaller)
|
|
1361
|
+
as padding length for the resampling operation.
|
|
1362
|
+
|
|
1363
|
+
Examples
|
|
1364
|
+
--------
|
|
1365
|
+
>>> import numpy as np
|
|
1366
|
+
>>> x = np.linspace(0, 10, 100)
|
|
1367
|
+
>>> y = np.sin(x)
|
|
1368
|
+
>>> offsets = np.random.normal(0, 0.1, 100)
|
|
1369
|
+
>>> warped_y = timewarp(x, y, offsets)
|
|
1370
|
+
"""
|
|
885
1371
|
if demean:
|
|
886
1372
|
demeanedoffset = timeoffset - np.mean(timeoffset)
|
|
887
1373
|
if debug:
|
|
888
1374
|
print("mean delay of ", np.mean(timeoffset), "seconds removed prior to resampling")
|
|
889
1375
|
else:
|
|
890
1376
|
demeanedoffset = timeoffset
|
|
891
|
-
sampletime = orig_x[1] - orig_x[0]
|
|
892
|
-
maxdevs = (np.min(demeanedoffset), np.max(demeanedoffset))
|
|
893
|
-
maxsamps = maxdevs / sampletime
|
|
1377
|
+
sampletime = float(orig_x[1] - orig_x[0])
|
|
1378
|
+
maxdevs = (float(np.min(demeanedoffset)), float(np.max(demeanedoffset)))
|
|
1379
|
+
maxsamps = (maxdevs[0] / sampletime, maxdevs[1] / sampletime)
|
|
894
1380
|
padlen = np.min([int(len(orig_x) // 2), int(30.0 / sampletime)])
|
|
895
1381
|
if debug:
|
|
896
1382
|
print("maximum deviation in samples:", maxsamps)
|