rapidtide 3.0.11__py3-none-any.whl → 3.1.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 +1049 -46
- rapidtide/RapidtideDataset.py +1533 -86
- rapidtide/_version.py +3 -3
- rapidtide/calccoherence.py +196 -29
- rapidtide/calcnullsimfunc.py +188 -40
- rapidtide/calcsimfunc.py +242 -42
- rapidtide/correlate.py +1203 -383
- 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 +53 -3
- rapidtide/data/examples/src/testglmfilt +5 -5
- rapidtide/data/examples/src/testhappy +29 -7
- 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/decorators.py +91 -0
- rapidtide/dlfilter.py +2226 -110
- rapidtide/dlfiltertorch.py +4842 -0
- rapidtide/externaltools.py +327 -12
- rapidtide/fMRIData_class.py +79 -40
- rapidtide/filter.py +1899 -810
- rapidtide/fit.py +2011 -581
- rapidtide/genericmultiproc.py +93 -18
- rapidtide/happy_supportfuncs.py +2047 -172
- rapidtide/helper_classes.py +584 -43
- rapidtide/io.py +2370 -372
- rapidtide/linfitfiltpass.py +346 -99
- rapidtide/makelaggedtcs.py +210 -24
- rapidtide/maskutil.py +448 -62
- rapidtide/miscmath.py +827 -121
- rapidtide/multiproc.py +210 -22
- rapidtide/patchmatch.py +242 -42
- rapidtide/peakeval.py +31 -31
- rapidtide/ppgproc.py +2203 -0
- rapidtide/qualitycheck.py +352 -39
- rapidtide/refinedelay.py +431 -57
- rapidtide/refineregressor.py +494 -189
- rapidtide/resample.py +671 -185
- rapidtide/scripts/applyppgproc.py +28 -0
- rapidtide/scripts/showxcorr_legacy.py +7 -7
- rapidtide/scripts/stupidramtricks.py +15 -17
- rapidtide/simFuncClasses.py +1052 -77
- rapidtide/simfuncfit.py +269 -69
- rapidtide/stats.py +540 -238
- rapidtide/tests/happycomp +9 -0
- rapidtide/tests/test_cleanregressor.py +1 -2
- 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 +11 -4
- rapidtide/tests/test_fullrunhappy_v4.py +10 -2
- rapidtide/tests/test_fullrunrapidtide_v7.py +1 -1
- rapidtide/tests/test_getparsers.py +11 -3
- rapidtide/tests/test_refinedelay.py +0 -1
- rapidtide/tests/test_simroundtrip.py +16 -8
- rapidtide/tests/test_stcorrelate.py +3 -1
- 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 +136 -23
- rapidtide/wiener2.py +113 -7
- rapidtide/workflows/adjustoffset.py +105 -3
- rapidtide/workflows/aligntcs.py +85 -2
- rapidtide/workflows/applydlfilter.py +87 -10
- rapidtide/workflows/applyppgproc.py +540 -0
- rapidtide/workflows/atlasaverage.py +210 -47
- rapidtide/workflows/atlastool.py +100 -3
- rapidtide/workflows/calcSimFuncMap.py +288 -69
- rapidtide/workflows/calctexticc.py +201 -9
- rapidtide/workflows/ccorrica.py +101 -6
- rapidtide/workflows/cleanregressor.py +165 -31
- rapidtide/workflows/delayvar.py +171 -23
- 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 +202 -51
- rapidtide/workflows/fixtr.py +73 -3
- rapidtide/workflows/gmscalc.py +113 -3
- rapidtide/workflows/happy.py +801 -199
- rapidtide/workflows/happy2std.py +144 -12
- rapidtide/workflows/happy_parser.py +163 -23
- 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 +98 -4
- rapidtide/workflows/pairwisemergenifti.py +85 -2
- rapidtide/workflows/parser_funcs.py +1421 -40
- rapidtide/workflows/physiofreq.py +137 -11
- rapidtide/workflows/pixelcomp.py +207 -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 +368 -76
- rapidtide/workflows/rapidtide2std.py +98 -2
- rapidtide/workflows/rapidtide_parser.py +109 -9
- rapidtide/workflows/refineDelayMap.py +144 -33
- rapidtide/workflows/refineRegressor.py +675 -96
- rapidtide/workflows/regressfrommaps.py +161 -37
- rapidtide/workflows/resamplenifti.py +85 -3
- rapidtide/workflows/resampletc.py +91 -3
- rapidtide/workflows/retrolagtcs.py +99 -9
- rapidtide/workflows/retroregress.py +176 -26
- rapidtide/workflows/roisummarize.py +174 -5
- rapidtide/workflows/runqualitycheck.py +71 -3
- rapidtide/workflows/showarbcorr.py +149 -6
- rapidtide/workflows/showhist.py +86 -2
- rapidtide/workflows/showstxcorr.py +160 -3
- rapidtide/workflows/showtc.py +159 -3
- rapidtide/workflows/showxcorrx.py +190 -10
- rapidtide/workflows/showxy.py +185 -15
- rapidtide/workflows/simdata.py +264 -38
- rapidtide/workflows/spatialfit.py +77 -2
- rapidtide/workflows/spatialmi.py +250 -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 +2971 -130
- rapidtide/workflows/utils.py +19 -14
- rapidtide/workflows/utils_doc.py +293 -0
- rapidtide/workflows/variabilityizer.py +116 -3
- {rapidtide-3.0.11.dist-info → rapidtide-3.1.1.dist-info}/METADATA +10 -8
- {rapidtide-3.0.11.dist-info → rapidtide-3.1.1.dist-info}/RECORD +144 -128
- {rapidtide-3.0.11.dist-info → rapidtide-3.1.1.dist-info}/entry_points.txt +1 -0
- {rapidtide-3.0.11.dist-info → rapidtide-3.1.1.dist-info}/WHEEL +0 -0
- {rapidtide-3.0.11.dist-info → rapidtide-3.1.1.dist-info}/licenses/LICENSE +0 -0
- {rapidtide-3.0.11.dist-info → rapidtide-3.1.1.dist-info}/top_level.txt +0 -0
rapidtide/filter.py
CHANGED
|
@@ -23,9 +23,13 @@ package.
|
|
|
23
23
|
|
|
24
24
|
import sys
|
|
25
25
|
import warnings
|
|
26
|
+
from typing import Optional, Tuple, Union
|
|
26
27
|
|
|
27
28
|
import matplotlib.pyplot as plt
|
|
28
29
|
import numpy as np
|
|
30
|
+
from numpy.typing import NDArray
|
|
31
|
+
|
|
32
|
+
from rapidtide.decorators import conditionaljit, conditionaljit2
|
|
29
33
|
|
|
30
34
|
with warnings.catch_warnings():
|
|
31
35
|
warnings.simplefilter("ignore")
|
|
@@ -43,70 +47,79 @@ if pyfftwpresent:
|
|
|
43
47
|
fftpack = pyfftw.interfaces.scipy_fftpack
|
|
44
48
|
pyfftw.interfaces.cache.enable()
|
|
45
49
|
|
|
46
|
-
# ----------------------------------------- Conditional imports ---------------------------------------
|
|
47
|
-
try:
|
|
48
|
-
from numba import jit
|
|
49
|
-
except ImportError:
|
|
50
|
-
donotusenumba = True
|
|
51
|
-
else:
|
|
52
|
-
donotusenumba = False
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
# ----------------------------------------- Conditional jit handling ----------------------------------
|
|
56
|
-
def conditionaljit():
|
|
57
|
-
def resdec(f):
|
|
58
|
-
global donotusenumba
|
|
59
|
-
if donotusenumba:
|
|
60
|
-
return f
|
|
61
|
-
return jit(f, nopython=True)
|
|
62
|
-
|
|
63
|
-
return resdec
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
def disablenumba():
|
|
67
|
-
global donotusenumba
|
|
68
|
-
donotusenumba = True
|
|
69
|
-
|
|
70
|
-
|
|
71
50
|
# --------------------------- Filtering functions -------------------------------------------------
|
|
72
51
|
# NB: No automatic padding for precalculated filters
|
|
73
52
|
|
|
74
53
|
|
|
75
54
|
@conditionaljit()
|
|
76
|
-
def padvec(
|
|
77
|
-
|
|
55
|
+
def padvec(
|
|
56
|
+
inputdata: NDArray,
|
|
57
|
+
padlen: int = 20,
|
|
58
|
+
avlen: int = 20,
|
|
59
|
+
padtype: str = "reflect",
|
|
60
|
+
debug: bool = False,
|
|
61
|
+
) -> NDArray:
|
|
62
|
+
"""
|
|
63
|
+
Returns a padded copy of the input data; padlen points of
|
|
78
64
|
filled data are prepended and appended to the input data to reduce
|
|
79
65
|
end effects when the data is then filtered. Filling can be "zero", "reflect", "cyclic", "constant",
|
|
80
66
|
or "constant+".
|
|
81
67
|
|
|
82
68
|
Parameters
|
|
83
69
|
----------
|
|
84
|
-
inputdata :
|
|
70
|
+
inputdata : NDArray
|
|
85
71
|
An array of any numerical type.
|
|
86
|
-
:param inputdata:
|
|
87
|
-
|
|
88
72
|
padlen : int, optional
|
|
89
|
-
The number of points to add to each end.
|
|
90
|
-
:param padlen:
|
|
91
|
-
|
|
73
|
+
The number of points to add to each end. Default is 20.
|
|
92
74
|
avlen : int, optional
|
|
93
|
-
The number of points to average when doing "constant+" padding.
|
|
94
|
-
|
|
75
|
+
The number of points to average when doing "constant+" padding. Default is 20.
|
|
95
76
|
padtype : str, optional
|
|
96
|
-
Method for padding data on the ends of the vector.
|
|
97
|
-
"constant", or "constant+".
|
|
98
|
-
|
|
77
|
+
Method for padding data on the ends of the vector. Options are "reflect", "zero", "cyclic",
|
|
78
|
+
"constant", or "constant+". Default is "reflect".
|
|
79
|
+
debug : bool, optional
|
|
80
|
+
If True, print debug information. Default is False.
|
|
99
81
|
|
|
100
82
|
Returns
|
|
101
83
|
-------
|
|
102
|
-
|
|
103
|
-
The input data, with padlen reflected points added to each end
|
|
104
|
-
|
|
84
|
+
NDArray
|
|
85
|
+
The input data, with `padlen` reflected points added to each end.
|
|
86
|
+
|
|
87
|
+
Notes
|
|
88
|
+
-----
|
|
89
|
+
This function is useful for reducing edge effects when filtering data. The padding methods are as follows:
|
|
90
|
+
- "reflect": pads by reflecting the input array around its edges.
|
|
91
|
+
- "zero": pads with zeros.
|
|
92
|
+
- "cyclic": pads by cycling the input array.
|
|
93
|
+
- "constant": pads with the first/last value of the input array.
|
|
94
|
+
- "constant+": pads with the mean of the first/last `avlen` points of the input array.
|
|
95
|
+
|
|
96
|
+
Examples
|
|
97
|
+
--------
|
|
98
|
+
>>> import numpy as np
|
|
99
|
+
>>> data = np.array([1, 2, 3, 4, 5])
|
|
100
|
+
>>> padded = padvec(data, padlen=2, padtype="reflect")
|
|
101
|
+
>>> print(padded)
|
|
102
|
+
[3 2 1 2 3 4 5 5 4]
|
|
103
|
+
|
|
104
|
+
>>> padded = padvec(data, padlen=2, padtype="zero")
|
|
105
|
+
>>> print(padded)
|
|
106
|
+
[0 0 1 2 3 4 5 0 0]
|
|
105
107
|
"""
|
|
106
108
|
if debug:
|
|
107
|
-
print(
|
|
109
|
+
print(
|
|
110
|
+
"padvec: padlen=",
|
|
111
|
+
padlen,
|
|
112
|
+
", avlen=",
|
|
113
|
+
avlen,
|
|
114
|
+
", padtype=",
|
|
115
|
+
padtype,
|
|
116
|
+
"len(inputdata)=",
|
|
117
|
+
len(inputdata),
|
|
118
|
+
)
|
|
108
119
|
if padlen > len(inputdata):
|
|
109
|
-
raise RuntimeError(
|
|
120
|
+
raise RuntimeError(
|
|
121
|
+
f"ERROR: padlen ({padlen}) is greater than input data length ({len(inputdata)})"
|
|
122
|
+
)
|
|
110
123
|
if avlen > padlen:
|
|
111
124
|
avlen = padlen
|
|
112
125
|
|
|
@@ -145,31 +158,48 @@ def padvec(inputdata, padlen=20, avlen=20, padtype="reflect", debug=False):
|
|
|
145
158
|
)
|
|
146
159
|
)
|
|
147
160
|
else:
|
|
148
|
-
raise ValueError(
|
|
161
|
+
raise ValueError(
|
|
162
|
+
"Padtype must be one of 'reflect', 'zero', 'cyclic', 'constant', or 'constant+'."
|
|
163
|
+
)
|
|
149
164
|
else:
|
|
150
165
|
return inputdata
|
|
151
166
|
|
|
152
167
|
|
|
153
168
|
@conditionaljit()
|
|
154
|
-
def unpadvec(inputdata, padlen=20):
|
|
155
|
-
|
|
156
|
-
|
|
169
|
+
def unpadvec(inputdata: NDArray, padlen: int = 20) -> NDArray:
|
|
170
|
+
"""
|
|
171
|
+
Returns input data with the end pads removed.
|
|
172
|
+
|
|
173
|
+
This function removes padding from both ends of an array. It is the inverse
|
|
174
|
+
operation of the `padvec` function, which adds padding to the array.
|
|
157
175
|
|
|
158
176
|
Parameters
|
|
159
177
|
----------
|
|
160
|
-
inputdata :
|
|
178
|
+
inputdata : NDArray
|
|
161
179
|
An array of any numerical type.
|
|
162
|
-
:param inputdata:
|
|
163
180
|
padlen : int, optional
|
|
164
|
-
The number of points to remove from each end.
|
|
165
|
-
:param padlen:
|
|
181
|
+
The number of points to remove from each end. Default is 20.
|
|
166
182
|
|
|
167
183
|
Returns
|
|
168
184
|
-------
|
|
169
|
-
|
|
170
|
-
The input data
|
|
171
|
-
|
|
172
|
-
|
|
185
|
+
NDArray
|
|
186
|
+
The input data with padding removed from both ends. If padlen is 0 or
|
|
187
|
+
negative, the original array is returned unchanged.
|
|
188
|
+
|
|
189
|
+
Notes
|
|
190
|
+
-----
|
|
191
|
+
When padlen is greater than 0, the function returns ``inputdata[padlen:-padlen]``.
|
|
192
|
+
If padlen is greater than or equal to the array length, an empty array will be returned.
|
|
193
|
+
|
|
194
|
+
Examples
|
|
195
|
+
--------
|
|
196
|
+
>>> import numpy as np
|
|
197
|
+
>>> data = np.array([1, 2, 3, 4, 5, 6, 7, 8])
|
|
198
|
+
>>> unpadvec(data, padlen=2)
|
|
199
|
+
array([3, 4, 5, 6])
|
|
200
|
+
|
|
201
|
+
>>> unpadvec(data, padlen=0)
|
|
202
|
+
array([1, 2, 3, 4, 5, 6, 7, 8])
|
|
173
203
|
"""
|
|
174
204
|
if padlen > 0:
|
|
175
205
|
return inputdata[padlen:-padlen]
|
|
@@ -177,36 +207,47 @@ def unpadvec(inputdata, padlen=20):
|
|
|
177
207
|
return inputdata
|
|
178
208
|
|
|
179
209
|
|
|
180
|
-
def ssmooth(xsize, ysize, zsize, sigma, inputdata):
|
|
181
|
-
|
|
210
|
+
def ssmooth(xsize: float, ysize: float, zsize: float, sigma: float, inputdata: NDArray) -> NDArray:
|
|
211
|
+
"""
|
|
212
|
+
Applies an isotropic gaussian spatial filter to a 3D array.
|
|
213
|
+
|
|
214
|
+
This function applies a Gaussian filter to 3D spatial data with isotropic
|
|
215
|
+
filtering parameters. The filter kernel width is specified in spatial units
|
|
216
|
+
and is converted to pixel units based on the array spacing parameters.
|
|
182
217
|
|
|
183
218
|
Parameters
|
|
184
219
|
----------
|
|
185
220
|
xsize : float
|
|
186
221
|
The array x step size in spatial units
|
|
187
|
-
:param xsize:
|
|
188
|
-
|
|
189
222
|
ysize : float
|
|
190
223
|
The array y step size in spatial units
|
|
191
|
-
:param ysize:
|
|
192
|
-
|
|
193
224
|
zsize : float
|
|
194
225
|
The array z step size in spatial units
|
|
195
|
-
:param zsize:
|
|
196
|
-
|
|
197
226
|
sigma : float
|
|
198
227
|
The width of the gaussian filter kernel in spatial units
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
inputdata : 3D numeric array
|
|
228
|
+
inputdata : NDArray
|
|
202
229
|
The spatial data to filter
|
|
203
|
-
:param inputdata:
|
|
204
230
|
|
|
205
231
|
Returns
|
|
206
232
|
-------
|
|
207
|
-
|
|
208
|
-
The filtered spatial data
|
|
209
|
-
|
|
233
|
+
NDArray
|
|
234
|
+
The filtered spatial data as a 3D float array
|
|
235
|
+
|
|
236
|
+
Notes
|
|
237
|
+
-----
|
|
238
|
+
The function uses `scipy.ndimage.gaussian_filter` internally, where the
|
|
239
|
+
sigma parameters are calculated as `sigma / step_size` for each dimension.
|
|
240
|
+
This ensures isotropic filtering when the same sigma value is used across
|
|
241
|
+
all spatial dimensions.
|
|
242
|
+
|
|
243
|
+
Examples
|
|
244
|
+
--------
|
|
245
|
+
>>> import numpy as np
|
|
246
|
+
>>> from scipy import ndimage
|
|
247
|
+
>>> data = np.random.rand(10, 10, 10)
|
|
248
|
+
>>> filtered = ssmooth(0.1, 0.1, 0.1, 0.2, data)
|
|
249
|
+
>>> print(filtered.shape)
|
|
250
|
+
(10, 10, 10)
|
|
210
251
|
"""
|
|
211
252
|
return ndimage.gaussian_filter(inputdata, [sigma / xsize, sigma / ysize, sigma / zsize])
|
|
212
253
|
|
|
@@ -214,53 +255,59 @@ def ssmooth(xsize, ysize, zsize, sigma, inputdata):
|
|
|
214
255
|
# - butterworth filters
|
|
215
256
|
# @conditionaljit()
|
|
216
257
|
def dolpfiltfilt(
|
|
217
|
-
Fs,
|
|
218
|
-
upperpass,
|
|
219
|
-
inputdata,
|
|
220
|
-
order,
|
|
221
|
-
padlen=20,
|
|
222
|
-
avlen=20,
|
|
223
|
-
padtype="reflect",
|
|
224
|
-
debug=False,
|
|
225
|
-
):
|
|
226
|
-
|
|
227
|
-
|
|
258
|
+
Fs: float,
|
|
259
|
+
upperpass: float,
|
|
260
|
+
inputdata: NDArray,
|
|
261
|
+
order: int,
|
|
262
|
+
padlen: int = 20,
|
|
263
|
+
avlen: int = 20,
|
|
264
|
+
padtype: str = "reflect",
|
|
265
|
+
debug: bool = False,
|
|
266
|
+
) -> NDArray:
|
|
267
|
+
"""
|
|
268
|
+
Performs a bidirectional (zero phase) Butterworth lowpass filter on an input vector
|
|
269
|
+
and returns the result. Ends are padded to reduce transients.
|
|
228
270
|
|
|
229
271
|
Parameters
|
|
230
272
|
----------
|
|
231
273
|
Fs : float
|
|
232
|
-
Sample rate in Hz
|
|
233
|
-
:param Fs:
|
|
234
|
-
|
|
274
|
+
Sample rate in Hz.
|
|
235
275
|
upperpass : float
|
|
236
|
-
Upper end of passband in Hz
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
inputdata : 1D numpy array
|
|
240
|
-
Input data to be filtered
|
|
241
|
-
:param inputdata:
|
|
242
|
-
|
|
276
|
+
Upper end of passband in Hz.
|
|
277
|
+
inputdata : NDArray
|
|
278
|
+
Input data to be filtered.
|
|
243
279
|
order : int
|
|
244
|
-
Order of Butterworth filter.
|
|
245
|
-
:param order:
|
|
246
|
-
|
|
280
|
+
Order of the Butterworth filter.
|
|
247
281
|
padlen : int, optional
|
|
248
|
-
Amount of points to reflect around each end of the input vector prior to filtering.
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
debug : boolean, optional
|
|
282
|
+
Amount of points to reflect around each end of the input vector prior to filtering.
|
|
283
|
+
Default is 20.
|
|
284
|
+
avlen : int, optional
|
|
285
|
+
Length of the averaging window used in padding. Default is 20.
|
|
286
|
+
padtype : str, optional
|
|
287
|
+
Type of padding to use. Options are 'reflect' or 'cyclic'. Default is 'reflect'.
|
|
288
|
+
debug : bool, optional
|
|
256
289
|
When True, internal states of the function will be printed to help debugging.
|
|
257
|
-
|
|
290
|
+
Default is False.
|
|
258
291
|
|
|
259
292
|
Returns
|
|
260
293
|
-------
|
|
261
|
-
filtereddata :
|
|
262
|
-
The filtered data
|
|
263
|
-
|
|
294
|
+
filtereddata : NDArray
|
|
295
|
+
The filtered data as a 1D float array.
|
|
296
|
+
|
|
297
|
+
Notes
|
|
298
|
+
-----
|
|
299
|
+
This function applies a zero-phase Butterworth filter using `scipy.signal.filtfilt`,
|
|
300
|
+
which eliminates phase distortion. Padding is applied before filtering to reduce
|
|
301
|
+
edge effects.
|
|
302
|
+
|
|
303
|
+
Examples
|
|
304
|
+
--------
|
|
305
|
+
>>> import numpy as np
|
|
306
|
+
>>> from scipy import signal
|
|
307
|
+
>>> Fs = 100.0
|
|
308
|
+
>>> upperpass = 20.0
|
|
309
|
+
>>> data = np.random.randn(1000)
|
|
310
|
+
>>> filtered = dolpfiltfilt(Fs, upperpass, data, order=4)
|
|
264
311
|
"""
|
|
265
312
|
if upperpass > Fs / 2.0:
|
|
266
313
|
upperpass = Fs / 2.0
|
|
@@ -277,9 +324,7 @@ def dolpfiltfilt(
|
|
|
277
324
|
signal.filtfilt(
|
|
278
325
|
b,
|
|
279
326
|
a,
|
|
280
|
-
padvec(
|
|
281
|
-
inputdata, padlen=padlen, avlen=avlen, padtype=padtype, debug=debug
|
|
282
|
-
),
|
|
327
|
+
padvec(inputdata, padlen=padlen, avlen=avlen, padtype=padtype, debug=debug),
|
|
283
328
|
).real,
|
|
284
329
|
padlen=padlen,
|
|
285
330
|
).astype(np.float64)
|
|
@@ -287,52 +332,58 @@ def dolpfiltfilt(
|
|
|
287
332
|
|
|
288
333
|
# @conditionaljit()
|
|
289
334
|
def dohpfiltfilt(
|
|
290
|
-
Fs,
|
|
291
|
-
lowerpass,
|
|
292
|
-
inputdata,
|
|
293
|
-
order,
|
|
294
|
-
padlen=20,
|
|
295
|
-
avlen=20,
|
|
296
|
-
padtype="reflect",
|
|
297
|
-
debug=False,
|
|
298
|
-
):
|
|
299
|
-
|
|
300
|
-
|
|
335
|
+
Fs: float,
|
|
336
|
+
lowerpass: float,
|
|
337
|
+
inputdata: NDArray,
|
|
338
|
+
order: int,
|
|
339
|
+
padlen: int = 20,
|
|
340
|
+
avlen: int = 20,
|
|
341
|
+
padtype: str = "reflect",
|
|
342
|
+
debug: bool = False,
|
|
343
|
+
) -> NDArray:
|
|
344
|
+
"""
|
|
345
|
+
Performs a bidirectional (zero phase) Butterworth highpass filter on an input vector
|
|
346
|
+
and returns the result. Ends are padded to reduce transients.
|
|
301
347
|
|
|
302
348
|
Parameters
|
|
303
349
|
----------
|
|
304
350
|
Fs : float
|
|
305
|
-
Sample rate in Hz
|
|
306
|
-
:param Fs:
|
|
307
|
-
|
|
351
|
+
Sample rate in Hz.
|
|
308
352
|
lowerpass : float
|
|
309
|
-
Lower end of passband in Hz
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
inputdata : 1D numpy array
|
|
313
|
-
Input data to be filtered
|
|
314
|
-
:param inputdata:
|
|
315
|
-
|
|
353
|
+
Lower end of passband in Hz.
|
|
354
|
+
inputdata : NDArray
|
|
355
|
+
Input signal to be filtered.
|
|
316
356
|
order : int
|
|
317
|
-
Order of Butterworth filter.
|
|
318
|
-
:param order:
|
|
319
|
-
|
|
357
|
+
Order of the Butterworth filter.
|
|
320
358
|
padlen : int, optional
|
|
321
|
-
Amount of points to reflect around each end of the input vector prior to filtering.
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
:param debug:
|
|
359
|
+
Amount of points to reflect around each end of the input vector prior to filtering.
|
|
360
|
+
Default is 20.
|
|
361
|
+
avlen : int, optional
|
|
362
|
+
Length of the averaging window used in padding. Default is 20.
|
|
363
|
+
padtype : str, optional
|
|
364
|
+
Type of padding to use. Options are 'reflect' or 'wrap'. Default is 'reflect'.
|
|
365
|
+
debug : bool, optional
|
|
366
|
+
If True, internal states of the function will be printed to help debugging.
|
|
367
|
+
Default is False.
|
|
331
368
|
|
|
332
369
|
Returns
|
|
333
370
|
-------
|
|
334
|
-
filtereddata :
|
|
335
|
-
The filtered data
|
|
371
|
+
filtereddata : NDArray
|
|
372
|
+
The filtered data with the same shape as inputdata.
|
|
373
|
+
|
|
374
|
+
Notes
|
|
375
|
+
-----
|
|
376
|
+
This function applies a zero-phase Butterworth highpass filter using `scipy.signal.filtfilt`,
|
|
377
|
+
which ensures no phase distortion in the filtered signal. Padding is applied before filtering
|
|
378
|
+
to minimize edge effects.
|
|
379
|
+
|
|
380
|
+
Examples
|
|
381
|
+
--------
|
|
382
|
+
>>> import numpy as np
|
|
383
|
+
>>> from scipy import signal
|
|
384
|
+
>>> Fs = 100.0
|
|
385
|
+
>>> data = np.random.randn(1000)
|
|
386
|
+
>>> filtered = dohpfiltfilt(Fs, 10.0, data, order=4, padlen=30)
|
|
336
387
|
"""
|
|
337
388
|
if lowerpass < 0.0:
|
|
338
389
|
lowerpass = 0.0
|
|
@@ -349,9 +400,7 @@ def dohpfiltfilt(
|
|
|
349
400
|
signal.filtfilt(
|
|
350
401
|
b,
|
|
351
402
|
a,
|
|
352
|
-
padvec(
|
|
353
|
-
inputdata, padlen=padlen, avlen=avlen, padtype=padtype, debug=debug
|
|
354
|
-
),
|
|
403
|
+
padvec(inputdata, padlen=padlen, avlen=avlen, padtype=padtype, debug=debug),
|
|
355
404
|
).real,
|
|
356
405
|
padlen=padlen,
|
|
357
406
|
)
|
|
@@ -359,57 +408,60 @@ def dohpfiltfilt(
|
|
|
359
408
|
|
|
360
409
|
# @conditionaljit()
|
|
361
410
|
def dobpfiltfilt(
|
|
362
|
-
Fs,
|
|
363
|
-
lowerpass,
|
|
364
|
-
upperpass,
|
|
365
|
-
inputdata,
|
|
366
|
-
order,
|
|
367
|
-
padlen=20,
|
|
368
|
-
avlen=20,
|
|
369
|
-
padtype="reflect",
|
|
370
|
-
debug=False,
|
|
371
|
-
):
|
|
372
|
-
|
|
373
|
-
|
|
411
|
+
Fs: float,
|
|
412
|
+
lowerpass: float,
|
|
413
|
+
upperpass: float,
|
|
414
|
+
inputdata: NDArray,
|
|
415
|
+
order: int,
|
|
416
|
+
padlen: int = 20,
|
|
417
|
+
avlen: int = 20,
|
|
418
|
+
padtype: str = "reflect",
|
|
419
|
+
debug: bool = False,
|
|
420
|
+
) -> NDArray:
|
|
421
|
+
"""
|
|
422
|
+
Performs a bidirectional (zero phase) Butterworth bandpass filter on an input vector
|
|
423
|
+
and returns the result. Ends are padded to reduce transients.
|
|
374
424
|
|
|
375
425
|
Parameters
|
|
376
426
|
----------
|
|
377
427
|
Fs : float
|
|
378
|
-
Sample rate in Hz
|
|
379
|
-
:param Fs:
|
|
380
|
-
|
|
428
|
+
Sample rate in Hz.
|
|
381
429
|
lowerpass : float
|
|
382
|
-
Lower end of passband in Hz
|
|
383
|
-
:param lowerpass:
|
|
384
|
-
|
|
430
|
+
Lower end of passband in Hz.
|
|
385
431
|
upperpass : float
|
|
386
|
-
Upper end of passband in Hz
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
inputdata : 1D numpy array
|
|
390
|
-
Input data to be filtered
|
|
391
|
-
:param inputdata:
|
|
392
|
-
|
|
432
|
+
Upper end of passband in Hz.
|
|
433
|
+
inputdata : NDArray
|
|
434
|
+
Input data to be filtered.
|
|
393
435
|
order : int
|
|
394
|
-
Order of Butterworth filter.
|
|
395
|
-
:param order:
|
|
396
|
-
|
|
436
|
+
Order of the Butterworth filter.
|
|
397
437
|
padlen : int, optional
|
|
398
|
-
Amount of points to reflect around each end of the input vector prior to filtering.
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
debug : boolean, optional
|
|
438
|
+
Amount of points to reflect around each end of the input vector prior to filtering.
|
|
439
|
+
Default is 20.
|
|
440
|
+
avlen : int, optional
|
|
441
|
+
Length of the averaging window used in padding. Default is 20.
|
|
442
|
+
padtype : str, optional
|
|
443
|
+
Type of padding to use. Options are 'reflect' or 'cyclic'. Default is 'reflect'.
|
|
444
|
+
debug : bool, optional
|
|
406
445
|
When True, internal states of the function will be printed to help debugging.
|
|
407
|
-
|
|
446
|
+
Default is False.
|
|
408
447
|
|
|
409
448
|
Returns
|
|
410
449
|
-------
|
|
411
|
-
filtereddata :
|
|
412
|
-
The filtered data
|
|
450
|
+
filtereddata : NDArray
|
|
451
|
+
The filtered data as a 1D float array.
|
|
452
|
+
|
|
453
|
+
Notes
|
|
454
|
+
-----
|
|
455
|
+
This function applies a zero-phase Butterworth bandpass filter using `scipy.signal.filtfilt`,
|
|
456
|
+
which eliminates phase distortion. Padding is applied before filtering to reduce edge effects.
|
|
457
|
+
|
|
458
|
+
Examples
|
|
459
|
+
--------
|
|
460
|
+
>>> import numpy as np
|
|
461
|
+
>>> from scipy import signal
|
|
462
|
+
>>> Fs = 100.0
|
|
463
|
+
>>> data = np.random.randn(1000)
|
|
464
|
+
>>> filtered = dobpfiltfilt(Fs, 10.0, 30.0, data, order=4, padlen=30)
|
|
413
465
|
"""
|
|
414
466
|
if upperpass > Fs / 2.0:
|
|
415
467
|
upperpass = Fs / 2.0
|
|
@@ -429,66 +481,98 @@ def dobpfiltfilt(
|
|
|
429
481
|
signal.filtfilt(
|
|
430
482
|
b,
|
|
431
483
|
a,
|
|
432
|
-
padvec(
|
|
433
|
-
inputdata, padlen=padlen, avlen=avlen, padtype=padtype, debug=debug
|
|
434
|
-
),
|
|
484
|
+
padvec(inputdata, padlen=padlen, avlen=avlen, padtype=padtype, debug=debug),
|
|
435
485
|
).real,
|
|
436
486
|
padlen=padlen,
|
|
437
487
|
)
|
|
438
488
|
|
|
439
489
|
|
|
440
490
|
# - direct filter with specified transfer function
|
|
441
|
-
def transferfuncfilt(inputdata, transferfunc):
|
|
442
|
-
|
|
491
|
+
def transferfuncfilt(inputdata: NDArray, transferfunc: NDArray) -> NDArray:
|
|
492
|
+
"""
|
|
493
|
+
Filters input data using a previously calculated transfer function.
|
|
494
|
+
|
|
495
|
+
This function applies frequency domain filtering by multiplying the input data's
|
|
496
|
+
Fourier transform with the transfer function, then transforms back to the time domain.
|
|
443
497
|
|
|
444
498
|
Parameters
|
|
445
499
|
----------
|
|
446
|
-
inputdata :
|
|
447
|
-
Input data to be filtered
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
transferfunc : 1D float array
|
|
451
|
-
The transfer function
|
|
452
|
-
:param transferfunc:
|
|
500
|
+
inputdata : NDArray
|
|
501
|
+
Input data to be filtered, array of real or complex values
|
|
502
|
+
transferfunc : NDArray
|
|
503
|
+
The transfer function, array of real or complex values with same length as inputdata
|
|
453
504
|
|
|
454
505
|
Returns
|
|
455
506
|
-------
|
|
456
|
-
|
|
457
|
-
Filtered input data
|
|
507
|
+
NDArray
|
|
508
|
+
Filtered input data as a 1D float array
|
|
509
|
+
|
|
510
|
+
Notes
|
|
511
|
+
-----
|
|
512
|
+
The filtering is performed in the frequency domain using the convolution theorem.
|
|
513
|
+
The transfer function should be designed to match the frequency response of the desired filter.
|
|
514
|
+
|
|
515
|
+
Examples
|
|
516
|
+
--------
|
|
517
|
+
>>> import numpy as np
|
|
518
|
+
>>> from scipy import fftpack
|
|
519
|
+
>>> # Create sample data
|
|
520
|
+
>>> data = np.random.randn(1024)
|
|
521
|
+
>>> # Create a simple low-pass filter transfer function
|
|
522
|
+
>>> freq = np.fft.fftfreq(len(data), 1.0)
|
|
523
|
+
>>> tf = np.abs(freq) < 0.1
|
|
524
|
+
>>> # Apply filter
|
|
525
|
+
>>> filtered_data = transferfuncfilt(data, tf)
|
|
458
526
|
"""
|
|
459
527
|
inputdata_trans = transferfunc * fftpack.fft(inputdata)
|
|
460
528
|
return fftpack.ifft(inputdata_trans).real
|
|
461
529
|
|
|
462
530
|
|
|
463
531
|
# - fft brickwall filters
|
|
464
|
-
def getlpfftfunc(Fs, upperpass, inputdata, debug=False):
|
|
465
|
-
|
|
532
|
+
def getlpfftfunc(Fs: float, upperpass: float, inputdata: NDArray, debug: bool = False) -> NDArray:
|
|
533
|
+
"""
|
|
534
|
+
Generates a brickwall lowpass transfer function.
|
|
535
|
+
|
|
536
|
+
This function creates a transfer function that acts as a brickwall lowpass filter
|
|
537
|
+
by setting frequencies above the cutoff to zero. The filter is designed in the
|
|
538
|
+
frequency domain using the FFT domain representation.
|
|
466
539
|
|
|
467
540
|
Parameters
|
|
468
541
|
----------
|
|
469
542
|
Fs : float
|
|
470
543
|
Sample rate in Hz
|
|
471
|
-
:param Fs:
|
|
472
|
-
|
|
473
544
|
upperpass : float
|
|
474
545
|
Upper end of passband in Hz
|
|
475
|
-
:param upperpass:
|
|
476
|
-
|
|
477
546
|
inputdata : 1D numpy array
|
|
478
547
|
Input data to be filtered
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
debug : boolean, optional
|
|
548
|
+
debug : bool, optional
|
|
482
549
|
When True, internal states of the function will be printed to help debugging.
|
|
483
|
-
|
|
550
|
+
Default is False.
|
|
484
551
|
|
|
485
552
|
Returns
|
|
486
553
|
-------
|
|
487
554
|
transferfunc : 1D float array
|
|
488
|
-
The transfer function
|
|
555
|
+
The transfer function with the lowpass filter characteristics
|
|
556
|
+
|
|
557
|
+
Notes
|
|
558
|
+
-----
|
|
559
|
+
The function creates a transfer function where frequencies below the cutoff
|
|
560
|
+
are set to 1.0 and frequencies above the cutoff are set to 0.0. The cutoff
|
|
561
|
+
frequency is determined by the ratio of upperpass to Fs, converted to bin
|
|
562
|
+
indices in the FFT domain.
|
|
563
|
+
|
|
564
|
+
Examples
|
|
565
|
+
--------
|
|
566
|
+
>>> import numpy as np
|
|
567
|
+
>>> Fs = 100.0
|
|
568
|
+
>>> upperpass = 20.0
|
|
569
|
+
>>> inputdata = np.random.rand(100)
|
|
570
|
+
>>> transfer_func = getlpfftfunc(Fs, upperpass, inputdata)
|
|
571
|
+
>>> print(transfer_func.shape)
|
|
572
|
+
(100,)
|
|
489
573
|
"""
|
|
490
574
|
transferfunc = np.ones(np.shape(inputdata), dtype=np.float64)
|
|
491
|
-
cutoffbin = int((upperpass / Fs) *
|
|
575
|
+
cutoffbin = int((upperpass / Fs) * len(transferfunc))
|
|
492
576
|
if debug:
|
|
493
577
|
print(
|
|
494
578
|
"getlpfftfunc - Fs, upperpass, len(inputdata):",
|
|
@@ -502,45 +586,59 @@ def getlpfftfunc(Fs, upperpass, inputdata, debug=False):
|
|
|
502
586
|
|
|
503
587
|
# @conditionaljit()
|
|
504
588
|
def dolpfftfilt(
|
|
505
|
-
Fs
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
589
|
+
Fs: float,
|
|
590
|
+
upperpass: float,
|
|
591
|
+
inputdata: NDArray,
|
|
592
|
+
padlen: int = 20,
|
|
593
|
+
avlen: int = 20,
|
|
594
|
+
padtype: str = "reflect",
|
|
595
|
+
debug: bool = False,
|
|
596
|
+
) -> NDArray:
|
|
597
|
+
"""
|
|
598
|
+
Performs an FFT brickwall lowpass filter on an input vector and returns the result.
|
|
599
|
+
Ends are padded to reduce transients.
|
|
509
600
|
|
|
510
601
|
Parameters
|
|
511
602
|
----------
|
|
512
603
|
Fs : float
|
|
513
|
-
Sample rate in Hz
|
|
514
|
-
:param Fs:
|
|
515
|
-
|
|
604
|
+
Sample rate in Hz.
|
|
516
605
|
upperpass : float
|
|
517
|
-
Upper end of passband in Hz
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
inputdata : 1D numpy array
|
|
521
|
-
Input data to be filtered
|
|
522
|
-
:param inputdata:
|
|
523
|
-
|
|
606
|
+
Upper end of passband in Hz.
|
|
607
|
+
inputdata : NDArray
|
|
608
|
+
Input data to be filtered, expected as a 1D numpy array.
|
|
524
609
|
padlen : int, optional
|
|
525
|
-
Amount of points to reflect around each end of the input vector prior to filtering.
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
debug : boolean, optional
|
|
610
|
+
Amount of points to reflect around each end of the input vector prior to filtering.
|
|
611
|
+
Default is 20.
|
|
612
|
+
avlen : int, optional
|
|
613
|
+
Length of the averaging window used in padding. Default is 20.
|
|
614
|
+
padtype : str, optional
|
|
615
|
+
Type of padding to use. Options are 'reflect' or 'wrap'. Default is 'reflect'.
|
|
616
|
+
debug : bool, optional
|
|
533
617
|
When True, internal states of the function will be printed to help debugging.
|
|
534
|
-
|
|
618
|
+
Default is False.
|
|
535
619
|
|
|
536
620
|
Returns
|
|
537
621
|
-------
|
|
538
|
-
|
|
539
|
-
The filtered data
|
|
622
|
+
NDArray
|
|
623
|
+
The filtered data as a 1D float array.
|
|
624
|
+
|
|
625
|
+
Notes
|
|
626
|
+
-----
|
|
627
|
+
This function applies a lowpass filter in the frequency domain using FFT. The input signal
|
|
628
|
+
is padded at both ends to minimize edge effects caused by the filtering process.
|
|
629
|
+
The padding is performed using the `padvec` function, and the inverse FFT is used to
|
|
630
|
+
transform the filtered signal back to the time domain.
|
|
631
|
+
|
|
632
|
+
Examples
|
|
633
|
+
--------
|
|
634
|
+
>>> import numpy as np
|
|
635
|
+
>>> from scipy import fftpack
|
|
636
|
+
>>> Fs = 100.0
|
|
637
|
+
>>> upperpass = 20.0
|
|
638
|
+
>>> data = np.random.randn(1000)
|
|
639
|
+
>>> filtered_data = dolpfftfilt(Fs, upperpass, data)
|
|
540
640
|
"""
|
|
541
|
-
padinputdata = padvec(
|
|
542
|
-
inputdata, padlen=padlen, avlen=avlen, padtype=padtype, debug=debug
|
|
543
|
-
)
|
|
641
|
+
padinputdata = padvec(inputdata, padlen=padlen, avlen=avlen, padtype=padtype, debug=debug)
|
|
544
642
|
inputdata_trans = fftpack.fft(padinputdata)
|
|
545
643
|
transferfunc = getlpfftfunc(Fs, upperpass, padinputdata, debug=debug)
|
|
546
644
|
inputdata_trans *= transferfunc
|
|
@@ -549,45 +647,57 @@ def dolpfftfilt(
|
|
|
549
647
|
|
|
550
648
|
# @conditionaljit()
|
|
551
649
|
def dohpfftfilt(
|
|
552
|
-
Fs
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
650
|
+
Fs: float,
|
|
651
|
+
lowerpass: float,
|
|
652
|
+
inputdata: NDArray,
|
|
653
|
+
padlen: int = 20,
|
|
654
|
+
avlen: int = 20,
|
|
655
|
+
padtype: str = "reflect",
|
|
656
|
+
debug: bool = False,
|
|
657
|
+
) -> NDArray:
|
|
658
|
+
"""
|
|
659
|
+
Performs an FFT brickwall highpass filter on an input vector and returns the result.
|
|
660
|
+
Ends are padded to reduce transients.
|
|
556
661
|
|
|
557
662
|
Parameters
|
|
558
663
|
----------
|
|
559
664
|
Fs : float
|
|
560
|
-
Sample rate in Hz
|
|
561
|
-
:param Fs:
|
|
562
|
-
|
|
665
|
+
Sample rate in Hz.
|
|
563
666
|
lowerpass : float
|
|
564
|
-
Lower end of passband in Hz
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
inputdata : 1D numpy array
|
|
568
|
-
Input data to be filtered
|
|
569
|
-
:param inputdata:
|
|
570
|
-
|
|
667
|
+
Lower end of passband in Hz.
|
|
668
|
+
inputdata : NDArray
|
|
669
|
+
Input data to be filtered, expected as a 1D numpy array.
|
|
571
670
|
padlen : int, optional
|
|
572
|
-
Amount of points to reflect around each end of the input vector prior to filtering.
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
debug : boolean, optional
|
|
671
|
+
Amount of points to reflect around each end of the input vector prior to filtering.
|
|
672
|
+
Default is 20.
|
|
673
|
+
avlen : int, optional
|
|
674
|
+
Length of the averaging window used in padding. Default is 20.
|
|
675
|
+
padtype : str, optional
|
|
676
|
+
Type of padding to use. Options are 'reflect' or 'cyclic'. Default is 'reflect'.
|
|
677
|
+
debug : bool, optional
|
|
580
678
|
When True, internal states of the function will be printed to help debugging.
|
|
581
|
-
|
|
679
|
+
Default is False.
|
|
582
680
|
|
|
583
681
|
Returns
|
|
584
682
|
-------
|
|
585
|
-
|
|
586
|
-
The filtered data
|
|
683
|
+
NDArray
|
|
684
|
+
The filtered data as a 1D float array.
|
|
685
|
+
|
|
686
|
+
Notes
|
|
687
|
+
-----
|
|
688
|
+
This function applies a highpass filter in the frequency domain using FFT.
|
|
689
|
+
The input signal is first padded to minimize edge effects, then transformed
|
|
690
|
+
into the frequency domain, filtered, and inverse transformed back to the time domain.
|
|
691
|
+
|
|
692
|
+
Examples
|
|
693
|
+
--------
|
|
694
|
+
>>> import numpy as np
|
|
695
|
+
>>> Fs = 100.0
|
|
696
|
+
>>> lowerpass = 10.0
|
|
697
|
+
>>> data = np.random.randn(1000)
|
|
698
|
+
>>> filtered = dohpfftfilt(Fs, lowerpass, data)
|
|
587
699
|
"""
|
|
588
|
-
padinputdata = padvec(
|
|
589
|
-
inputdata, padlen=padlen, avlen=avlen, padtype=padtype, debug=debug
|
|
590
|
-
)
|
|
700
|
+
padinputdata = padvec(inputdata, padlen=padlen, avlen=avlen, padtype=padtype, debug=debug)
|
|
591
701
|
inputdata_trans = fftpack.fft(padinputdata)
|
|
592
702
|
transferfunc = 1.0 - getlpfftfunc(Fs, lowerpass, padinputdata, debug=debug)
|
|
593
703
|
inputdata_trans *= transferfunc
|
|
@@ -596,56 +706,64 @@ def dohpfftfilt(
|
|
|
596
706
|
|
|
597
707
|
# @conditionaljit()
|
|
598
708
|
def dobpfftfilt(
|
|
599
|
-
Fs,
|
|
600
|
-
lowerpass,
|
|
601
|
-
upperpass,
|
|
602
|
-
inputdata,
|
|
603
|
-
padlen=20,
|
|
604
|
-
avlen=20,
|
|
605
|
-
padtype="reflect",
|
|
606
|
-
debug=False,
|
|
607
|
-
):
|
|
608
|
-
|
|
609
|
-
|
|
709
|
+
Fs: float,
|
|
710
|
+
lowerpass: float,
|
|
711
|
+
upperpass: float,
|
|
712
|
+
inputdata: NDArray,
|
|
713
|
+
padlen: int = 20,
|
|
714
|
+
avlen: int = 20,
|
|
715
|
+
padtype: str = "reflect",
|
|
716
|
+
debug: bool = False,
|
|
717
|
+
) -> NDArray:
|
|
718
|
+
"""
|
|
719
|
+
Performs an FFT brickwall bandpass filter on an input vector and returns the result.
|
|
720
|
+
Ends are padded to reduce transients.
|
|
610
721
|
|
|
611
722
|
Parameters
|
|
612
723
|
----------
|
|
613
724
|
Fs : float
|
|
614
|
-
Sample rate in Hz
|
|
615
|
-
:param Fs:
|
|
616
|
-
|
|
725
|
+
Sample rate in Hz.
|
|
617
726
|
lowerpass : float
|
|
618
|
-
Lower end of passband in Hz
|
|
619
|
-
:param lowerpass:
|
|
620
|
-
|
|
727
|
+
Lower end of passband in Hz.
|
|
621
728
|
upperpass : float
|
|
622
|
-
Upper end of passband in Hz
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
inputdata : 1D numpy array
|
|
626
|
-
Input data to be filtered
|
|
627
|
-
:param inputdata:
|
|
628
|
-
|
|
729
|
+
Upper end of passband in Hz.
|
|
730
|
+
inputdata : NDArray
|
|
731
|
+
Input data to be filtered, expected as a 1D numpy array.
|
|
629
732
|
padlen : int, optional
|
|
630
|
-
Amount of points to reflect around each end of the input vector prior to filtering.
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
733
|
+
Amount of points to reflect around each end of the input vector prior to filtering.
|
|
734
|
+
Default is 20.
|
|
735
|
+
avlen : int, optional
|
|
736
|
+
Length of averaging window for padding; used only if `padtype` is 'mean'.
|
|
737
|
+
Default is 20.
|
|
738
|
+
padtype : str, optional
|
|
739
|
+
Type of padding to use. Options are 'reflect', 'mean', or 'wrap'.
|
|
740
|
+
Default is 'reflect'.
|
|
741
|
+
debug : bool, optional
|
|
638
742
|
When True, internal states of the function will be printed to help debugging.
|
|
639
|
-
|
|
743
|
+
Default is False.
|
|
640
744
|
|
|
641
745
|
Returns
|
|
642
746
|
-------
|
|
643
|
-
|
|
644
|
-
The filtered data
|
|
747
|
+
NDArray
|
|
748
|
+
The filtered data as a 1D float array, with the same shape as inputdata.
|
|
749
|
+
|
|
750
|
+
Notes
|
|
751
|
+
-----
|
|
752
|
+
This function applies a brickwall bandpass filter in the frequency domain using FFT.
|
|
753
|
+
The input signal is first padded to minimize edge effects, then transformed into
|
|
754
|
+
the frequency domain, filtered, and transformed back. Padding is applied using
|
|
755
|
+
the specified `padtype` and `padlen`.
|
|
756
|
+
|
|
757
|
+
Examples
|
|
758
|
+
--------
|
|
759
|
+
>>> import numpy as np
|
|
760
|
+
>>> from scipy import signal
|
|
761
|
+
>>> fs = 100.0
|
|
762
|
+
>>> t = np.linspace(0, 1, int(fs), endpoint=False)
|
|
763
|
+
>>> x = np.sin(2 * np.pi * 10 * t) + 0.5 * np.sin(2 * np.pi * 25 * t)
|
|
764
|
+
>>> filtered = dobpfftfilt(fs, 5, 15, x, padlen=30)
|
|
645
765
|
"""
|
|
646
|
-
padinputdata = padvec(
|
|
647
|
-
inputdata, padlen=padlen, avlen=avlen, padtype=padtype, debug=debug
|
|
648
|
-
)
|
|
766
|
+
padinputdata = padvec(inputdata, padlen=padlen, avlen=avlen, padtype=padtype, debug=debug)
|
|
649
767
|
inputdata_trans = fftpack.fft(padinputdata)
|
|
650
768
|
transferfunc = getlpfftfunc(Fs, upperpass, padinputdata, debug=debug) * (
|
|
651
769
|
1.0 - getlpfftfunc(Fs, lowerpass, padinputdata, debug=debug)
|
|
@@ -656,35 +774,56 @@ def dobpfftfilt(
|
|
|
656
774
|
|
|
657
775
|
# - fft trapezoidal filters
|
|
658
776
|
# @conditionaljit()
|
|
659
|
-
def getlptrapfftfunc(
|
|
660
|
-
|
|
777
|
+
def getlptrapfftfunc(
|
|
778
|
+
Fs: float, upperpass: float, upperstop: float, inputdata: NDArray, debug: bool = False
|
|
779
|
+
) -> NDArray:
|
|
780
|
+
"""
|
|
781
|
+
Generate a trapezoidal lowpass transfer function for filtering.
|
|
782
|
+
|
|
783
|
+
This function creates a transfer function with a trapezoidal transition band
|
|
784
|
+
between the passband and stopband, suitable for use in spectral filtering
|
|
785
|
+
operations. The resulting transfer function can be applied to frequency-domain
|
|
786
|
+
data to perform lowpass filtering.
|
|
661
787
|
|
|
662
788
|
Parameters
|
|
663
789
|
----------
|
|
664
790
|
Fs : float
|
|
665
|
-
Sample rate in Hz
|
|
666
|
-
:param Fs:
|
|
667
|
-
|
|
791
|
+
Sample rate in Hz.
|
|
668
792
|
upperpass : float
|
|
669
|
-
Upper
|
|
670
|
-
:param upperpass:
|
|
671
|
-
|
|
793
|
+
Upper edge of the passband in Hz.
|
|
672
794
|
upperstop : float
|
|
673
|
-
Lower
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
debug : boolean, optional
|
|
681
|
-
When True, internal states of the function will be printed to help debugging.
|
|
682
|
-
:param debug:
|
|
795
|
+
Lower edge of the stopband in Hz.
|
|
796
|
+
inputdata : NDArray
|
|
797
|
+
Input data array (typically frequency domain data) to determine the
|
|
798
|
+
length and shape of the transfer function.
|
|
799
|
+
debug : bool, optional
|
|
800
|
+
If True, print internal state information for debugging purposes.
|
|
801
|
+
Default is False.
|
|
683
802
|
|
|
684
803
|
Returns
|
|
685
804
|
-------
|
|
686
|
-
|
|
687
|
-
|
|
805
|
+
NDArray
|
|
806
|
+
A 1D float array representing the transfer function. The array has the
|
|
807
|
+
same length as `inputdata` and contains values between 0 and 1,
|
|
808
|
+
indicating the attenuation at each frequency bin.
|
|
809
|
+
|
|
810
|
+
Notes
|
|
811
|
+
-----
|
|
812
|
+
The transition from passband to stopband is linear (trapezoidal), with
|
|
813
|
+
the transition region defined between `upperpass` and `upperstop`.
|
|
814
|
+
The function assumes that `upperpass < upperstop` and that both are
|
|
815
|
+
within the Nyquist frequency range (0 to Fs/2).
|
|
816
|
+
|
|
817
|
+
Examples
|
|
818
|
+
--------
|
|
819
|
+
>>> import numpy as np
|
|
820
|
+
>>> Fs = 100.0
|
|
821
|
+
>>> upperpass = 20.0
|
|
822
|
+
>>> upperstop = 30.0
|
|
823
|
+
>>> inputdata = np.zeros(100)
|
|
824
|
+
>>> tf = getlptrapfftfunc(Fs, upperpass, upperstop, inputdata)
|
|
825
|
+
>>> print(tf.shape)
|
|
826
|
+
(100,)
|
|
688
827
|
"""
|
|
689
828
|
transferfunc = np.ones(np.shape(inputdata), dtype="float64")
|
|
690
829
|
passbin = int((upperpass / Fs) * np.shape(transferfunc)[0])
|
|
@@ -709,7 +848,64 @@ def getlptrapfftfunc(Fs, upperpass, upperstop, inputdata, debug=False):
|
|
|
709
848
|
|
|
710
849
|
|
|
711
850
|
# @conditionaljit()
|
|
712
|
-
def getlptransfunc(
|
|
851
|
+
def getlptransfunc(
|
|
852
|
+
Fs: float,
|
|
853
|
+
inputdata: NDArray,
|
|
854
|
+
upperpass: Optional[float] = None,
|
|
855
|
+
upperstop: Optional[float] = None,
|
|
856
|
+
type: str = "brickwall",
|
|
857
|
+
debug: bool = False,
|
|
858
|
+
) -> NDArray:
|
|
859
|
+
"""
|
|
860
|
+
Compute the low-pass transfer function for a given input signal.
|
|
861
|
+
|
|
862
|
+
This function generates a transfer function based on the specified type
|
|
863
|
+
(brickwall, Gaussian, or trapezoidal) to be used for filtering purposes.
|
|
864
|
+
The transfer function is applied in the frequency domain to filter the input data.
|
|
865
|
+
|
|
866
|
+
Parameters
|
|
867
|
+
----------
|
|
868
|
+
Fs : float
|
|
869
|
+
Sampling frequency of the input signal in Hz.
|
|
870
|
+
inputdata : NDArray
|
|
871
|
+
Input signal data, used to determine the length of the transfer function.
|
|
872
|
+
upperpass : float, optional
|
|
873
|
+
Upper passband frequency in Hz. Must be specified.
|
|
874
|
+
upperstop : float, optional
|
|
875
|
+
Upper stopband frequency in Hz. Only used for 'trapezoidal' type.
|
|
876
|
+
Defaults to 1.05 * upperpass if not specified.
|
|
877
|
+
type : str, optional
|
|
878
|
+
Type of transfer function to generate. Options are:
|
|
879
|
+
- "brickwall": Ideal low-pass filter with sharp cutoff.
|
|
880
|
+
- "gaussian": Gaussian-shaped transition.
|
|
881
|
+
- "trapezoidal": Trapezoidal transition between pass and stop bands.
|
|
882
|
+
Default is "brickwall".
|
|
883
|
+
debug : bool, optional
|
|
884
|
+
If True, prints debug information and displays the transfer function plot.
|
|
885
|
+
Default is False.
|
|
886
|
+
|
|
887
|
+
Returns
|
|
888
|
+
-------
|
|
889
|
+
NDArray
|
|
890
|
+
The computed low-pass transfer function with the same shape as `inputdata`.
|
|
891
|
+
|
|
892
|
+
Notes
|
|
893
|
+
-----
|
|
894
|
+
- For 'brickwall' type, the transfer function is 1.0 in the passband and 0.0 in the stopband.
|
|
895
|
+
- For 'gaussian' type, the transition is smoothed using a Gaussian function.
|
|
896
|
+
- For 'trapezoidal' type, a linear transition is applied between pass and stop bands.
|
|
897
|
+
- The function uses the sampling frequency `Fs` to map frequencies to the normalized frequency axis.
|
|
898
|
+
|
|
899
|
+
Examples
|
|
900
|
+
--------
|
|
901
|
+
>>> import numpy as np
|
|
902
|
+
>>> input_signal = np.random.rand(1024)
|
|
903
|
+
>>> Fs = 100.0
|
|
904
|
+
>>> upperpass = 20.0
|
|
905
|
+
>>> tf = getlptransfunc(Fs, input_signal, upperpass, type='gaussian')
|
|
906
|
+
>>> print(tf.shape)
|
|
907
|
+
(1024,)
|
|
908
|
+
"""
|
|
713
909
|
if upperpass is None:
|
|
714
910
|
print("getlptransfunc: upperpass must be specified")
|
|
715
911
|
sys.exit()
|
|
@@ -773,7 +969,55 @@ def getlptransfunc(Fs, inputdata, upperpass=None, upperstop=None, type="brickwal
|
|
|
773
969
|
return transferfunc
|
|
774
970
|
|
|
775
971
|
|
|
776
|
-
def gethptransfunc(
|
|
972
|
+
def gethptransfunc(
|
|
973
|
+
Fs: float,
|
|
974
|
+
inputdata: NDArray,
|
|
975
|
+
lowerstop: Optional[float] = None,
|
|
976
|
+
lowerpass: Optional[float] = None,
|
|
977
|
+
type: str = "brickwall",
|
|
978
|
+
debug: bool = False,
|
|
979
|
+
) -> NDArray:
|
|
980
|
+
"""
|
|
981
|
+
Compute high-pass transfer function from low-pass transfer function.
|
|
982
|
+
|
|
983
|
+
This function generates a high-pass transfer function by subtracting a
|
|
984
|
+
low-pass transfer function from unity. The low-pass function is computed
|
|
985
|
+
using the `getlptransfunc` function with appropriate parameters.
|
|
986
|
+
|
|
987
|
+
Parameters
|
|
988
|
+
----------
|
|
989
|
+
Fs : float
|
|
990
|
+
Sampling frequency in Hz.
|
|
991
|
+
inputdata : NDArray
|
|
992
|
+
Input data array used for transfer function computation.
|
|
993
|
+
lowerstop : float, optional
|
|
994
|
+
Lower stop frequency for trapezoidal filter type. Required for
|
|
995
|
+
trapezoidal type, ignored for brickwall type.
|
|
996
|
+
lowerpass : float, optional
|
|
997
|
+
Lower pass frequency (cutoff frequency) for the high-pass filter.
|
|
998
|
+
Must be specified.
|
|
999
|
+
type : str, default="brickwall"
|
|
1000
|
+
Type of filter transfer function. Options are "brickwall" or "trapezoidal".
|
|
1001
|
+
debug : bool, default=False
|
|
1002
|
+
If True, enables debug output during computation.
|
|
1003
|
+
|
|
1004
|
+
Returns
|
|
1005
|
+
-------
|
|
1006
|
+
NDArray
|
|
1007
|
+
High-pass transfer function array with same shape as inputdata.
|
|
1008
|
+
|
|
1009
|
+
Notes
|
|
1010
|
+
-----
|
|
1011
|
+
For trapezoidal filter type, the lower stop frequency is used as the
|
|
1012
|
+
upper pass frequency for the underlying low-pass function.
|
|
1013
|
+
|
|
1014
|
+
Examples
|
|
1015
|
+
--------
|
|
1016
|
+
>>> import numpy as np
|
|
1017
|
+
>>> Fs = 100.0
|
|
1018
|
+
>>> data = np.linspace(0, 1, 100)
|
|
1019
|
+
>>> hp_func = gethptransfunc(Fs, data, lowerpass=10.0, type="brickwall")
|
|
1020
|
+
"""
|
|
777
1021
|
if lowerpass is None:
|
|
778
1022
|
print("gethptransfunc: lowerpass must be specified")
|
|
779
1023
|
sys.exit()
|
|
@@ -795,53 +1039,67 @@ def gethptransfunc(Fs, inputdata, lowerstop=None, lowerpass=None, type="brickwal
|
|
|
795
1039
|
|
|
796
1040
|
# @conditionaljit()
|
|
797
1041
|
def dolptransfuncfilt(
|
|
798
|
-
Fs,
|
|
799
|
-
inputdata,
|
|
800
|
-
upperpass=None,
|
|
801
|
-
upperstop=None,
|
|
802
|
-
type="brickwall",
|
|
803
|
-
padlen=20,
|
|
804
|
-
avlen=20,
|
|
805
|
-
padtype="reflect",
|
|
806
|
-
debug=False,
|
|
807
|
-
):
|
|
808
|
-
|
|
809
|
-
|
|
1042
|
+
Fs: float,
|
|
1043
|
+
inputdata: NDArray,
|
|
1044
|
+
upperpass: Optional[float] = None,
|
|
1045
|
+
upperstop: Optional[float] = None,
|
|
1046
|
+
type: str = "brickwall",
|
|
1047
|
+
padlen: int = 20,
|
|
1048
|
+
avlen: int = 20,
|
|
1049
|
+
padtype: str = "reflect",
|
|
1050
|
+
debug: bool = False,
|
|
1051
|
+
) -> NDArray:
|
|
1052
|
+
"""
|
|
1053
|
+
Performs an FFT filter with a Gaussian lowpass transfer function on an input vector
|
|
1054
|
+
and returns the result. Ends are padded to reduce transients.
|
|
810
1055
|
|
|
811
1056
|
Parameters
|
|
812
1057
|
----------
|
|
813
1058
|
Fs : float
|
|
814
|
-
Sample rate in Hz
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
upperpass : float
|
|
818
|
-
Upper end of passband in Hz
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
1059
|
+
Sample rate in Hz.
|
|
1060
|
+
inputdata : NDArray
|
|
1061
|
+
Input data to be filtered, expected as a 1D array.
|
|
1062
|
+
upperpass : float, optional
|
|
1063
|
+
Upper end of the passband in Hz. If not specified, the filter will use a default
|
|
1064
|
+
value based on the data characteristics.
|
|
1065
|
+
upperstop : float, optional
|
|
1066
|
+
Upper end of the stopband in Hz. If not specified, the filter will use a default
|
|
1067
|
+
value based on the data characteristics.
|
|
1068
|
+
type : str, optional
|
|
1069
|
+
Type of transfer function to use. Default is "brickwall". Other options may include
|
|
1070
|
+
"gaussian", "butterworth", etc., depending on implementation of `getlptransfunc`.
|
|
825
1071
|
padlen : int, optional
|
|
826
|
-
Amount of points to reflect around each end of the input vector prior to filtering.
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
debug :
|
|
1072
|
+
Amount of points to reflect around each end of the input vector prior to filtering.
|
|
1073
|
+
Default is 20.
|
|
1074
|
+
avlen : int, optional
|
|
1075
|
+
Length of the averaging window used in padding. Default is 20.
|
|
1076
|
+
padtype : str, optional
|
|
1077
|
+
Type of padding to use. Options include "reflect", "wrap", "constant", etc.
|
|
1078
|
+
Default is "reflect".
|
|
1079
|
+
debug : bool, optional
|
|
834
1080
|
When True, internal states of the function will be printed to help debugging.
|
|
835
|
-
|
|
1081
|
+
A plot of the transfer function will be displayed if debug is enabled.
|
|
836
1082
|
|
|
837
1083
|
Returns
|
|
838
1084
|
-------
|
|
839
|
-
|
|
840
|
-
The filtered data
|
|
1085
|
+
NDArray
|
|
1086
|
+
The filtered data as a 1D float array of the same length as inputdata.
|
|
1087
|
+
|
|
1088
|
+
Notes
|
|
1089
|
+
-----
|
|
1090
|
+
This function applies a frequency-domain filter by computing the FFT of the padded input,
|
|
1091
|
+
applying a transfer function, and then inverse transforming the result. Padding is applied
|
|
1092
|
+
to reduce edge effects caused by the FFT.
|
|
1093
|
+
|
|
1094
|
+
Examples
|
|
1095
|
+
--------
|
|
1096
|
+
>>> import numpy as np
|
|
1097
|
+
>>> Fs = 100.0
|
|
1098
|
+
>>> t = np.linspace(0, 1, int(Fs), endpoint=False)
|
|
1099
|
+
>>> signal = np.sin(2 * np.pi * 10 * t)
|
|
1100
|
+
>>> filtered = dolptransfuncfilt(Fs, signal, upperpass=20.0)
|
|
841
1101
|
"""
|
|
842
|
-
padinputdata = padvec(
|
|
843
|
-
inputdata, padlen=padlen, avlen=avlen, padtype=padtype, debug=debug
|
|
844
|
-
)
|
|
1102
|
+
padinputdata = padvec(inputdata, padlen=padlen, avlen=avlen, padtype=padtype, debug=debug)
|
|
845
1103
|
inputdata_trans = fftpack.fft(padinputdata)
|
|
846
1104
|
transferfunc = getlptransfunc(
|
|
847
1105
|
Fs, padinputdata, upperpass=upperpass, upperstop=upperstop, type=type
|
|
@@ -853,7 +1111,7 @@ def dolptransfuncfilt(
|
|
|
853
1111
|
)
|
|
854
1112
|
fig = plt.figure()
|
|
855
1113
|
ax = fig.add_subplot(111)
|
|
856
|
-
ax.set_title("LP Transfer function -
|
|
1114
|
+
ax.set_title(f"LP Transfer function - {type}, upperpass={upperpass:.2f}")
|
|
857
1115
|
plt.plot(freqaxis, transferfunc)
|
|
858
1116
|
plt.show()
|
|
859
1117
|
inputdata_trans *= transferfunc
|
|
@@ -862,59 +1120,65 @@ def dolptransfuncfilt(
|
|
|
862
1120
|
|
|
863
1121
|
# @conditionaljit()
|
|
864
1122
|
def dohptransfuncfilt(
|
|
865
|
-
Fs,
|
|
866
|
-
inputdata,
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
type="brickwall",
|
|
870
|
-
padlen=20,
|
|
871
|
-
avlen=20,
|
|
872
|
-
padtype="reflect",
|
|
873
|
-
debug=False,
|
|
874
|
-
):
|
|
875
|
-
|
|
876
|
-
|
|
1123
|
+
Fs: float,
|
|
1124
|
+
inputdata: NDArray,
|
|
1125
|
+
lowerpass: float,
|
|
1126
|
+
lowerstop: Optional[float | None] = None,
|
|
1127
|
+
type: str = "brickwall",
|
|
1128
|
+
padlen: int = 20,
|
|
1129
|
+
avlen: int = 20,
|
|
1130
|
+
padtype: str = "reflect",
|
|
1131
|
+
debug: bool = False,
|
|
1132
|
+
) -> NDArray:
|
|
1133
|
+
"""
|
|
1134
|
+
Performs an FFT filter with a trapezoidal highpass transfer function on an input vector
|
|
1135
|
+
and returns the result. Ends are padded to reduce transients.
|
|
877
1136
|
|
|
878
1137
|
Parameters
|
|
879
1138
|
----------
|
|
880
1139
|
Fs : float
|
|
881
|
-
Sample rate in Hz
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
lowerstop : float
|
|
885
|
-
Upper end of stopband in Hz
|
|
886
|
-
:param lowerstop:
|
|
887
|
-
|
|
1140
|
+
Sample rate in Hz.
|
|
1141
|
+
inputdata : NDArray
|
|
1142
|
+
Input data to be filtered.
|
|
888
1143
|
lowerpass : float
|
|
889
|
-
Lower end of passband in Hz
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
:param inputdata:
|
|
895
|
-
|
|
1144
|
+
Lower end of the passband in Hz.
|
|
1145
|
+
lowerstop : float, optional
|
|
1146
|
+
Upper end of the stopband in Hz. If not provided, it is set to `lowerpass / 1.05`.
|
|
1147
|
+
type : str, optional
|
|
1148
|
+
Type of transfer function to use. Default is "brickwall".
|
|
896
1149
|
padlen : int, optional
|
|
897
|
-
Amount of points to reflect around each end of the input vector prior to filtering.
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
debug : boolean, optional
|
|
1150
|
+
Amount of points to reflect around each end of the input vector prior to filtering.
|
|
1151
|
+
Default is 20.
|
|
1152
|
+
avlen : int, optional
|
|
1153
|
+
Length of the averaging window used in padding. Default is 20.
|
|
1154
|
+
padtype : str, optional
|
|
1155
|
+
Type of padding to use. Options are "reflect" or "wrap". Default is "reflect".
|
|
1156
|
+
debug : bool, optional
|
|
905
1157
|
When True, internal states of the function will be printed to help debugging.
|
|
906
|
-
|
|
1158
|
+
Default is False.
|
|
907
1159
|
|
|
908
1160
|
Returns
|
|
909
1161
|
-------
|
|
910
|
-
filtereddata :
|
|
911
|
-
The filtered data
|
|
1162
|
+
filtereddata : NDArray
|
|
1163
|
+
The filtered data as a 1D float array.
|
|
1164
|
+
|
|
1165
|
+
Notes
|
|
1166
|
+
-----
|
|
1167
|
+
This function applies a highpass filter in the frequency domain using FFT. The input signal
|
|
1168
|
+
is padded to reduce edge effects, then filtered using a transfer function, and finally
|
|
1169
|
+
unpadded to return the result.
|
|
1170
|
+
|
|
1171
|
+
Examples
|
|
1172
|
+
--------
|
|
1173
|
+
>>> import numpy as np
|
|
1174
|
+
>>> Fs = 100.0
|
|
1175
|
+
>>> t = np.linspace(0, 1, int(Fs), endpoint=False)
|
|
1176
|
+
>>> signal = np.sin(2 * np.pi * 10 * t)
|
|
1177
|
+
>>> filtered = dohptransfuncfilt(Fs, signal, lowerpass=5.0)
|
|
912
1178
|
"""
|
|
913
1179
|
if lowerstop is None:
|
|
914
1180
|
lowerstop = lowerpass * (1.0 / 1.05)
|
|
915
|
-
padinputdata = padvec(
|
|
916
|
-
inputdata, padlen=padlen, avlen=avlen, padtype=padtype, debug=debug
|
|
917
|
-
)
|
|
1181
|
+
padinputdata = padvec(inputdata, padlen=padlen, avlen=avlen, padtype=padtype, debug=debug)
|
|
918
1182
|
inputdata_trans = fftpack.fft(padinputdata)
|
|
919
1183
|
transferfunc = getlptransfunc(
|
|
920
1184
|
Fs, padinputdata, upperpass=lowerstop, upperstop=lowerpass, type=type
|
|
@@ -926,7 +1190,7 @@ def dohptransfuncfilt(
|
|
|
926
1190
|
)
|
|
927
1191
|
fig = plt.figure()
|
|
928
1192
|
ax = fig.add_subplot(111)
|
|
929
|
-
ax.set_title("HP Transfer function -
|
|
1193
|
+
ax.set_title(f"HP Transfer function - {type}, lowerpass={lowerpass:.2f}")
|
|
930
1194
|
plt.plot(freqaxis, transferfunc)
|
|
931
1195
|
plt.show()
|
|
932
1196
|
inputdata_trans *= 1.0 - transferfunc
|
|
@@ -935,61 +1199,72 @@ def dohptransfuncfilt(
|
|
|
935
1199
|
|
|
936
1200
|
# @conditionaljit()
|
|
937
1201
|
def dobptransfuncfilt(
|
|
938
|
-
Fs,
|
|
939
|
-
inputdata,
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
upperstop=None,
|
|
944
|
-
type="brickwall",
|
|
945
|
-
padlen=20,
|
|
946
|
-
avlen=20,
|
|
947
|
-
padtype="reflect",
|
|
948
|
-
debug=False,
|
|
949
|
-
):
|
|
950
|
-
|
|
951
|
-
|
|
1202
|
+
Fs: float,
|
|
1203
|
+
inputdata: NDArray,
|
|
1204
|
+
lowerpass: float,
|
|
1205
|
+
upperpass: float,
|
|
1206
|
+
lowerstop: Optional[float] = None,
|
|
1207
|
+
upperstop: Optional[float] = None,
|
|
1208
|
+
type: str = "brickwall",
|
|
1209
|
+
padlen: int = 20,
|
|
1210
|
+
avlen: int = 20,
|
|
1211
|
+
padtype: str = "reflect",
|
|
1212
|
+
debug: bool = False,
|
|
1213
|
+
) -> NDArray:
|
|
1214
|
+
"""
|
|
1215
|
+
Performs an FFT filter with a trapezoidal highpass transfer function on an input vector
|
|
1216
|
+
and returns the result. Ends are padded to reduce transients.
|
|
952
1217
|
|
|
953
1218
|
Parameters
|
|
954
1219
|
----------
|
|
955
1220
|
Fs : float
|
|
956
|
-
Sample rate in Hz
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
lowerstop : float
|
|
960
|
-
Upper end of stopband in Hz
|
|
961
|
-
:param lowerstop:
|
|
962
|
-
|
|
1221
|
+
Sample rate in Hz.
|
|
1222
|
+
inputdata : NDArray
|
|
1223
|
+
Input data to be filtered.
|
|
963
1224
|
lowerpass : float
|
|
964
|
-
Lower end of passband in Hz
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
1225
|
+
Lower end of passband in Hz.
|
|
1226
|
+
upperpass : float
|
|
1227
|
+
Upper end of passband in Hz.
|
|
1228
|
+
lowerstop : float, optional
|
|
1229
|
+
Upper end of stopband in Hz. If not provided, it is computed as `lowerpass / 1.05`.
|
|
1230
|
+
upperstop : float, optional
|
|
1231
|
+
Lower end of stopband in Hz. If not provided, it is computed as `upperpass * 1.05`.
|
|
1232
|
+
type : str, optional
|
|
1233
|
+
Type of transfer function to use. Default is "brickwall".
|
|
971
1234
|
padlen : int, optional
|
|
972
|
-
Amount of points to reflect around each end of the input vector prior to filtering.
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
debug : boolean, optional
|
|
1235
|
+
Amount of points to reflect around each end of the input vector prior to filtering.
|
|
1236
|
+
Default is 20.
|
|
1237
|
+
avlen : int, optional
|
|
1238
|
+
Length of the averaging window used in padding. Default is 20.
|
|
1239
|
+
padtype : str, optional
|
|
1240
|
+
Type of padding to use. Options are "reflect" or "wrap". Default is "reflect".
|
|
1241
|
+
debug : bool, optional
|
|
980
1242
|
When True, internal states of the function will be printed to help debugging.
|
|
981
|
-
|
|
1243
|
+
Default is False.
|
|
982
1244
|
|
|
983
1245
|
Returns
|
|
984
1246
|
-------
|
|
985
|
-
filtereddata :
|
|
986
|
-
The filtered data
|
|
1247
|
+
filtereddata : NDArray
|
|
1248
|
+
The filtered data as a 1D float array.
|
|
1249
|
+
|
|
1250
|
+
Notes
|
|
1251
|
+
-----
|
|
1252
|
+
This function applies a bandpass filter in the frequency domain using FFT. It pads the input
|
|
1253
|
+
data to minimize edge effects and applies a transfer function that combines a lowpass and
|
|
1254
|
+
highpass response. The resulting filtered signal is returned after inverse FFT and unpadding.
|
|
1255
|
+
|
|
1256
|
+
Examples
|
|
1257
|
+
--------
|
|
1258
|
+
>>> import numpy as np
|
|
1259
|
+
>>> from scipy import fftpack
|
|
1260
|
+
>>> Fs = 100.0
|
|
1261
|
+
>>> t = np.linspace(0, 1, int(Fs), endpoint=False)
|
|
1262
|
+
>>> signal = np.sin(2 * np.pi * 10 * t)
|
|
1263
|
+
>>> filtered = dobptransfuncfilt(Fs, signal, 5.0, 15.0)
|
|
987
1264
|
"""
|
|
988
1265
|
if lowerstop is None:
|
|
989
1266
|
lowerstop = lowerpass * (1.0 / 1.05)
|
|
990
|
-
padinputdata = padvec(
|
|
991
|
-
inputdata, padlen=padlen, avlen=avlen, padtype=padtype, debug=debug
|
|
992
|
-
)
|
|
1267
|
+
padinputdata = padvec(inputdata, padlen=padlen, avlen=avlen, padtype=padtype, debug=debug)
|
|
993
1268
|
inputdata_trans = fftpack.fft(padinputdata)
|
|
994
1269
|
transferfunc = getlptransfunc(
|
|
995
1270
|
Fs,
|
|
@@ -1007,9 +1282,7 @@ def dobptransfuncfilt(
|
|
|
1007
1282
|
fig = plt.figure()
|
|
1008
1283
|
ax = fig.add_subplot(111)
|
|
1009
1284
|
ax.set_title(
|
|
1010
|
-
"BP Transfer function - "
|
|
1011
|
-
+ type
|
|
1012
|
-
+ ", lowerpass={:.2f}, upperpass={:.2f}".format(lowerpass, upperpass)
|
|
1285
|
+
f"BP Transfer function - {type}, lowerpass={lowerpass:.2f}, upperpass={upperpass:.2f}"
|
|
1013
1286
|
)
|
|
1014
1287
|
plt.plot(freqaxis, transferfunc)
|
|
1015
1288
|
plt.show()
|
|
@@ -1019,56 +1292,61 @@ def dobptransfuncfilt(
|
|
|
1019
1292
|
|
|
1020
1293
|
# @conditionaljit()
|
|
1021
1294
|
def dolptrapfftfilt(
|
|
1022
|
-
Fs,
|
|
1023
|
-
upperpass,
|
|
1024
|
-
upperstop,
|
|
1025
|
-
inputdata,
|
|
1026
|
-
padlen=20,
|
|
1027
|
-
avlen=20,
|
|
1028
|
-
padtype="reflect",
|
|
1029
|
-
debug=False,
|
|
1030
|
-
):
|
|
1031
|
-
|
|
1032
|
-
|
|
1295
|
+
Fs: float,
|
|
1296
|
+
upperpass: float,
|
|
1297
|
+
upperstop: float,
|
|
1298
|
+
inputdata: NDArray,
|
|
1299
|
+
padlen: int = 20,
|
|
1300
|
+
avlen: int = 20,
|
|
1301
|
+
padtype: str = "reflect",
|
|
1302
|
+
debug: bool = False,
|
|
1303
|
+
) -> NDArray:
|
|
1304
|
+
"""
|
|
1305
|
+
Performs an FFT filter with a trapezoidal lowpass transfer function on an input vector
|
|
1306
|
+
and returns the result. Ends are padded to reduce transients.
|
|
1033
1307
|
|
|
1034
1308
|
Parameters
|
|
1035
1309
|
----------
|
|
1036
1310
|
Fs : float
|
|
1037
|
-
Sample rate in Hz
|
|
1038
|
-
:param Fs:
|
|
1039
|
-
|
|
1311
|
+
Sample rate in Hz.
|
|
1040
1312
|
upperpass : float
|
|
1041
|
-
Upper end of passband in Hz
|
|
1042
|
-
:param upperpass:
|
|
1043
|
-
|
|
1313
|
+
Upper end of the passband in Hz.
|
|
1044
1314
|
upperstop : float
|
|
1045
|
-
Lower end of stopband in Hz
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
inputdata : 1D numpy array
|
|
1049
|
-
Input data to be filtered
|
|
1050
|
-
:param inputdata:
|
|
1051
|
-
|
|
1315
|
+
Lower end of the stopband in Hz.
|
|
1316
|
+
inputdata : NDArray
|
|
1317
|
+
Input data to be filtered, as a 1D numpy array.
|
|
1052
1318
|
padlen : int, optional
|
|
1053
|
-
Amount of points to reflect around each end of the input vector prior to filtering.
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
debug : boolean, optional
|
|
1319
|
+
Amount of points to reflect around each end of the input vector prior to filtering.
|
|
1320
|
+
Default is 20.
|
|
1321
|
+
avlen : int, optional
|
|
1322
|
+
Length of the averaging window used in padding. Default is 20.
|
|
1323
|
+
padtype : str, optional
|
|
1324
|
+
Type of padding to use. Options are 'reflect' or 'wrap'. Default is 'reflect'.
|
|
1325
|
+
debug : bool, optional
|
|
1061
1326
|
When True, internal states of the function will be printed to help debugging.
|
|
1062
|
-
|
|
1327
|
+
Default is False.
|
|
1063
1328
|
|
|
1064
1329
|
Returns
|
|
1065
1330
|
-------
|
|
1066
|
-
filtereddata :
|
|
1067
|
-
The filtered data
|
|
1331
|
+
filtereddata : NDArray
|
|
1332
|
+
The filtered data as a 1D float array.
|
|
1333
|
+
|
|
1334
|
+
Notes
|
|
1335
|
+
-----
|
|
1336
|
+
This function applies a trapezoidal lowpass filter in the frequency domain using FFT.
|
|
1337
|
+
The input signal is first padded to reduce edge effects, then filtered using a
|
|
1338
|
+
transfer function, and finally the padding is removed to return the filtered signal.
|
|
1339
|
+
|
|
1340
|
+
Examples
|
|
1341
|
+
--------
|
|
1342
|
+
>>> import numpy as np
|
|
1343
|
+
>>> Fs = 100.0
|
|
1344
|
+
>>> upperpass = 20.0
|
|
1345
|
+
>>> upperstop = 25.0
|
|
1346
|
+
>>> data = np.random.randn(1000)
|
|
1347
|
+
>>> filtered = dolptrapfftfilt(Fs, upperpass, upperstop, data)
|
|
1068
1348
|
"""
|
|
1069
|
-
padinputdata = padvec(
|
|
1070
|
-
inputdata, padlen=padlen, avlen=avlen, padtype=padtype, debug=debug
|
|
1071
|
-
)
|
|
1349
|
+
padinputdata = padvec(inputdata, padlen=padlen, avlen=avlen, padtype=padtype, debug=debug)
|
|
1072
1350
|
inputdata_trans = fftpack.fft(padinputdata)
|
|
1073
1351
|
transferfunc = getlptrapfftfunc(Fs, upperpass, upperstop, padinputdata, debug=debug)
|
|
1074
1352
|
inputdata_trans *= transferfunc
|
|
@@ -1077,56 +1355,62 @@ def dolptrapfftfilt(
|
|
|
1077
1355
|
|
|
1078
1356
|
# @conditionaljit()
|
|
1079
1357
|
def dohptrapfftfilt(
|
|
1080
|
-
Fs,
|
|
1081
|
-
lowerstop,
|
|
1082
|
-
lowerpass,
|
|
1083
|
-
inputdata,
|
|
1084
|
-
padlen=20,
|
|
1085
|
-
avlen=20,
|
|
1086
|
-
padtype="reflect",
|
|
1087
|
-
debug=False,
|
|
1088
|
-
):
|
|
1089
|
-
|
|
1090
|
-
|
|
1358
|
+
Fs: float,
|
|
1359
|
+
lowerstop: float,
|
|
1360
|
+
lowerpass: float,
|
|
1361
|
+
inputdata: NDArray,
|
|
1362
|
+
padlen: int = 20,
|
|
1363
|
+
avlen: int = 20,
|
|
1364
|
+
padtype: str = "reflect",
|
|
1365
|
+
debug: bool = False,
|
|
1366
|
+
) -> NDArray:
|
|
1367
|
+
"""
|
|
1368
|
+
Performs an FFT filter with a trapezoidal highpass transfer function on an input vector
|
|
1369
|
+
and returns the result. Ends are padded to reduce transients.
|
|
1091
1370
|
|
|
1092
1371
|
Parameters
|
|
1093
1372
|
----------
|
|
1094
1373
|
Fs : float
|
|
1095
|
-
Sample rate in Hz
|
|
1096
|
-
:param Fs:
|
|
1097
|
-
|
|
1374
|
+
Sample rate in Hz.
|
|
1098
1375
|
lowerstop : float
|
|
1099
|
-
Upper end of stopband in Hz
|
|
1100
|
-
:param lowerstop:
|
|
1101
|
-
|
|
1376
|
+
Upper end of stopband in Hz.
|
|
1102
1377
|
lowerpass : float
|
|
1103
|
-
Lower end of passband in Hz
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
inputdata : 1D numpy array
|
|
1107
|
-
Input data to be filtered
|
|
1108
|
-
:param inputdata:
|
|
1109
|
-
|
|
1378
|
+
Lower end of passband in Hz.
|
|
1379
|
+
inputdata : NDArray
|
|
1380
|
+
Input data to be filtered, expected as a 1D numpy array.
|
|
1110
1381
|
padlen : int, optional
|
|
1111
|
-
Amount of points to reflect around each end of the input vector prior to filtering.
|
|
1112
|
-
|
|
1113
|
-
|
|
1114
|
-
|
|
1115
|
-
|
|
1116
|
-
|
|
1117
|
-
|
|
1118
|
-
debug : boolean, optional
|
|
1382
|
+
Amount of points to reflect around each end of the input vector prior to filtering.
|
|
1383
|
+
Default is 20.
|
|
1384
|
+
avlen : int, optional
|
|
1385
|
+
Length of the averaging window used in padding. Default is 20.
|
|
1386
|
+
padtype : str, optional
|
|
1387
|
+
Type of padding to use. Options are 'reflect' or 'cyclic'. Default is 'reflect'.
|
|
1388
|
+
debug : bool, optional
|
|
1119
1389
|
When True, internal states of the function will be printed to help debugging.
|
|
1120
|
-
|
|
1390
|
+
Default is False.
|
|
1121
1391
|
|
|
1122
1392
|
Returns
|
|
1123
1393
|
-------
|
|
1124
|
-
filtereddata :
|
|
1125
|
-
The filtered data
|
|
1394
|
+
filtereddata : NDArray
|
|
1395
|
+
The filtered data as a 1D float array.
|
|
1396
|
+
|
|
1397
|
+
Notes
|
|
1398
|
+
-----
|
|
1399
|
+
This function applies a trapezoidal highpass filter in the frequency domain using FFT.
|
|
1400
|
+
The input signal is first padded using the specified padding method to reduce edge effects.
|
|
1401
|
+
The filter transfer function is constructed using `getlptrapfftfunc`, and the filtered
|
|
1402
|
+
signal is obtained by inverse FFT.
|
|
1403
|
+
|
|
1404
|
+
Examples
|
|
1405
|
+
--------
|
|
1406
|
+
>>> import numpy as np
|
|
1407
|
+
>>> Fs = 100.0
|
|
1408
|
+
>>> lowerstop = 5.0
|
|
1409
|
+
>>> lowerpass = 10.0
|
|
1410
|
+
>>> data = np.random.randn(1000)
|
|
1411
|
+
>>> filtered = dohptrapfftfilt(Fs, lowerstop, lowerpass, data)
|
|
1126
1412
|
"""
|
|
1127
|
-
padinputdata = padvec(
|
|
1128
|
-
inputdata, padlen=padlen, avlen=avlen, padtype=padtype, debug=debug
|
|
1129
|
-
)
|
|
1413
|
+
padinputdata = padvec(inputdata, padlen=padlen, avlen=avlen, padtype=padtype, debug=debug)
|
|
1130
1414
|
inputdata_trans = fftpack.fft(padinputdata)
|
|
1131
1415
|
transferfunc = 1.0 - getlptrapfftfunc(Fs, lowerstop, lowerpass, padinputdata, debug=debug)
|
|
1132
1416
|
inputdata_trans *= transferfunc
|
|
@@ -1135,66 +1419,66 @@ def dohptrapfftfilt(
|
|
|
1135
1419
|
|
|
1136
1420
|
# @conditionaljit()
|
|
1137
1421
|
def dobptrapfftfilt(
|
|
1138
|
-
Fs,
|
|
1139
|
-
lowerstop,
|
|
1140
|
-
lowerpass,
|
|
1141
|
-
upperpass,
|
|
1142
|
-
upperstop,
|
|
1143
|
-
inputdata,
|
|
1144
|
-
padlen=20,
|
|
1145
|
-
avlen=20,
|
|
1146
|
-
padtype="reflect",
|
|
1147
|
-
debug=False,
|
|
1148
|
-
):
|
|
1149
|
-
|
|
1150
|
-
|
|
1422
|
+
Fs: float,
|
|
1423
|
+
lowerstop: float,
|
|
1424
|
+
lowerpass: float,
|
|
1425
|
+
upperpass: float,
|
|
1426
|
+
upperstop: float,
|
|
1427
|
+
inputdata: NDArray,
|
|
1428
|
+
padlen: int = 20,
|
|
1429
|
+
avlen: int = 20,
|
|
1430
|
+
padtype: str = "reflect",
|
|
1431
|
+
debug: bool = False,
|
|
1432
|
+
) -> NDArray:
|
|
1433
|
+
"""
|
|
1434
|
+
Performs an FFT filter with a trapezoidal bandpass transfer function on an input vector
|
|
1435
|
+
and returns the result. Ends are padded to reduce transients.
|
|
1151
1436
|
|
|
1152
1437
|
Parameters
|
|
1153
1438
|
----------
|
|
1154
1439
|
Fs : float
|
|
1155
|
-
Sample rate in Hz
|
|
1156
|
-
:param Fs:
|
|
1157
|
-
|
|
1440
|
+
Sample rate in Hz.
|
|
1158
1441
|
lowerstop : float
|
|
1159
|
-
Upper end of stopband in Hz
|
|
1160
|
-
:param lowerstop:
|
|
1161
|
-
|
|
1442
|
+
Upper end of the lower stopband in Hz.
|
|
1162
1443
|
lowerpass : float
|
|
1163
|
-
Lower end of passband in Hz
|
|
1164
|
-
:param lowerpass:
|
|
1165
|
-
|
|
1444
|
+
Lower end of the lower passband in Hz.
|
|
1166
1445
|
upperpass : float
|
|
1167
|
-
Upper end of passband in Hz
|
|
1168
|
-
:param upperpass:
|
|
1169
|
-
|
|
1446
|
+
Upper end of the upper passband in Hz.
|
|
1170
1447
|
upperstop : float
|
|
1171
|
-
Lower end of stopband in Hz
|
|
1172
|
-
|
|
1173
|
-
|
|
1174
|
-
inputdata : 1D numpy array
|
|
1175
|
-
Input data to be filtered
|
|
1176
|
-
:param inputdata:
|
|
1177
|
-
|
|
1448
|
+
Lower end of the upper stopband in Hz.
|
|
1449
|
+
inputdata : NDArray
|
|
1450
|
+
Input data to be filtered, expected as a 1D numpy array.
|
|
1178
1451
|
padlen : int, optional
|
|
1179
|
-
Amount of points to reflect around each end of the input vector prior to filtering.
|
|
1180
|
-
|
|
1181
|
-
|
|
1182
|
-
|
|
1183
|
-
|
|
1184
|
-
|
|
1185
|
-
|
|
1186
|
-
debug : boolean, optional
|
|
1452
|
+
Amount of points to reflect around each end of the input vector prior to filtering.
|
|
1453
|
+
Default is 20.
|
|
1454
|
+
avlen : int, optional
|
|
1455
|
+
Length of the averaging window used in padding. Default is 20.
|
|
1456
|
+
padtype : str, optional
|
|
1457
|
+
Type of padding to use. Options are 'reflect' or 'wrap'. Default is 'reflect'.
|
|
1458
|
+
debug : bool, optional
|
|
1187
1459
|
When True, internal states of the function will be printed to help debugging.
|
|
1188
|
-
|
|
1460
|
+
Default is False.
|
|
1189
1461
|
|
|
1190
1462
|
Returns
|
|
1191
1463
|
-------
|
|
1192
|
-
|
|
1193
|
-
The filtered data
|
|
1464
|
+
NDArray
|
|
1465
|
+
The filtered data as a 1D float array.
|
|
1466
|
+
|
|
1467
|
+
Notes
|
|
1468
|
+
-----
|
|
1469
|
+
This function applies a trapezoidal bandpass filter in the frequency domain using FFT.
|
|
1470
|
+
The input signal is first padded to minimize edge effects, then transformed into the
|
|
1471
|
+
frequency domain, multiplied by the transfer function, and finally inverse transformed
|
|
1472
|
+
back to the time domain.
|
|
1473
|
+
|
|
1474
|
+
Examples
|
|
1475
|
+
--------
|
|
1476
|
+
>>> import numpy as np
|
|
1477
|
+
>>> Fs = 100.0
|
|
1478
|
+
>>> data = np.random.randn(1000)
|
|
1479
|
+
>>> filtered = dobptrapfftfilt(Fs, 10, 15, 25, 30, data, padlen=50)
|
|
1194
1480
|
"""
|
|
1195
|
-
padinputdata = padvec(
|
|
1196
|
-
inputdata, padlen=padlen, avlen=avlen, padtype=padtype, debug=debug
|
|
1197
|
-
)
|
|
1481
|
+
padinputdata = padvec(inputdata, padlen=padlen, avlen=avlen, padtype=padtype, debug=debug)
|
|
1198
1482
|
inputdata_trans = fftpack.fft(padinputdata)
|
|
1199
1483
|
if debug:
|
|
1200
1484
|
print(
|
|
@@ -1220,8 +1504,43 @@ def dobptrapfftfilt(
|
|
|
1220
1504
|
# We use a fixed SNR across all frequencies in this example.
|
|
1221
1505
|
#
|
|
1222
1506
|
# Written 2015 by Dan Stowell. Public domain.
|
|
1223
|
-
def wiener_deconvolution(signal, kernel, lambd):
|
|
1224
|
-
"
|
|
1507
|
+
def wiener_deconvolution(signal: NDArray, kernel: NDArray, lambd: float) -> NDArray:
|
|
1508
|
+
"""Perform Wiener deconvolution on a signal.
|
|
1509
|
+
|
|
1510
|
+
This function applies Wiener deconvolution to remove blur from a signal using
|
|
1511
|
+
the Wiener filter in the frequency domain. The regularization parameter `lambd`
|
|
1512
|
+
represents the signal-to-noise ratio in the Fourier domain.
|
|
1513
|
+
|
|
1514
|
+
Parameters
|
|
1515
|
+
----------
|
|
1516
|
+
signal : NDArray
|
|
1517
|
+
Input signal to be deconvolved, 1D array.
|
|
1518
|
+
kernel : NDArray
|
|
1519
|
+
Convolution kernel (point spread function), 1D array.
|
|
1520
|
+
lambd : float
|
|
1521
|
+
Regularization parameter representing the signal-to-noise ratio in
|
|
1522
|
+
the Fourier domain. Higher values correspond to more smoothing.
|
|
1523
|
+
|
|
1524
|
+
Returns
|
|
1525
|
+
-------
|
|
1526
|
+
NDArray
|
|
1527
|
+
Deconvolved signal, same length as input signal.
|
|
1528
|
+
|
|
1529
|
+
Notes
|
|
1530
|
+
-----
|
|
1531
|
+
The Wiener deconvolution formula in frequency domain is:
|
|
1532
|
+
Y = X * H* / (|H|² + λ²)
|
|
1533
|
+
|
|
1534
|
+
where X is the Fourier transform of the input signal, H is the Fourier
|
|
1535
|
+
transform of the kernel, and H* is the complex conjugate of H.
|
|
1536
|
+
|
|
1537
|
+
Examples
|
|
1538
|
+
--------
|
|
1539
|
+
>>> import numpy as np
|
|
1540
|
+
>>> signal = np.array([1, 2, 3, 2, 1])
|
|
1541
|
+
>>> kernel = np.array([1, 0.5, 0.25])
|
|
1542
|
+
>>> result = wiener_deconvolution(signal, kernel, lambd=0.1)
|
|
1543
|
+
"""
|
|
1225
1544
|
kernel = np.hstack(
|
|
1226
1545
|
(kernel, np.zeros(len(signal) - len(kernel)))
|
|
1227
1546
|
) # zero pad the kernel to same length
|
|
@@ -1233,66 +1552,83 @@ def wiener_deconvolution(signal, kernel, lambd):
|
|
|
1233
1552
|
return deconvolved
|
|
1234
1553
|
|
|
1235
1554
|
|
|
1236
|
-
def pspec(inputdata):
|
|
1237
|
-
|
|
1555
|
+
def pspec(inputdata: NDArray) -> NDArray:
|
|
1556
|
+
"""
|
|
1557
|
+
Calculate the power spectrum of an input signal.
|
|
1238
1558
|
|
|
1239
1559
|
Parameters
|
|
1240
1560
|
----------
|
|
1241
|
-
inputdata:
|
|
1242
|
-
Input data
|
|
1561
|
+
inputdata : NDArray
|
|
1562
|
+
Input signal data array of shape (n,) where n is the number of samples.
|
|
1243
1563
|
|
|
1244
1564
|
Returns
|
|
1245
1565
|
-------
|
|
1246
|
-
|
|
1247
|
-
The power spectrum of the input signal.
|
|
1248
|
-
|
|
1566
|
+
NDArray
|
|
1567
|
+
The power spectrum of the input signal as a 1D numpy array of shape (n,).
|
|
1568
|
+
Each element represents the power at the corresponding frequency bin.
|
|
1569
|
+
|
|
1570
|
+
Notes
|
|
1571
|
+
-----
|
|
1572
|
+
This function computes the power spectrum using the Fast Fourier Transform (FFT).
|
|
1573
|
+
The power spectrum is calculated as the square root of the product of the FFT
|
|
1574
|
+
and its complex conjugate, which gives the magnitude of the frequency components.
|
|
1575
|
+
|
|
1576
|
+
Examples
|
|
1577
|
+
--------
|
|
1578
|
+
>>> import numpy as np
|
|
1579
|
+
>>> from scipy import fftpack
|
|
1580
|
+
>>> signal = np.sin(2 * np.pi * 5 * np.linspace(0, 1, 100))
|
|
1581
|
+
>>> spectrum = pspec(signal)
|
|
1582
|
+
>>> print(spectrum.shape)
|
|
1583
|
+
(100,)
|
|
1249
1584
|
"""
|
|
1250
1585
|
S = fftpack.fft(inputdata)
|
|
1251
1586
|
return np.sqrt(S * np.conj(S))
|
|
1252
1587
|
|
|
1253
1588
|
|
|
1254
|
-
def spectralflatness(spectrum):
|
|
1589
|
+
def spectralflatness(spectrum: NDArray) -> float:
|
|
1255
1590
|
return np.exp(np.mean(np.log(spectrum))) / np.mean(spectrum)
|
|
1256
1591
|
|
|
1257
1592
|
|
|
1258
|
-
def spectrum(
|
|
1259
|
-
|
|
1260
|
-
|
|
1593
|
+
def spectrum(
|
|
1594
|
+
inputdata: NDArray, Fs: float = 1.0, mode: str = "power", trim: bool = True
|
|
1595
|
+
) -> Tuple[NDArray, Union[NDArray, None]]:
|
|
1596
|
+
"""
|
|
1597
|
+
Compute the spectral flatness of a spectrum.
|
|
1598
|
+
|
|
1599
|
+
Spectral flatness is a measure of how much a spectrum resembles white noise.
|
|
1600
|
+
It is defined as the ratio of the geometric mean to the arithmetic mean of the spectrum.
|
|
1261
1601
|
|
|
1262
1602
|
Parameters
|
|
1263
1603
|
----------
|
|
1264
|
-
|
|
1265
|
-
Input
|
|
1266
|
-
:param inputdata:
|
|
1267
|
-
|
|
1268
|
-
Fs : float, optional
|
|
1269
|
-
Sample rate in Hz. Defaults to 1.0
|
|
1270
|
-
:param Fs:
|
|
1271
|
-
|
|
1272
|
-
mode : {'real', 'imag', 'mag', 'phase', 'power'}, optional
|
|
1273
|
-
The type of spectrum to return. Default is 'power'.
|
|
1274
|
-
:param mode:
|
|
1275
|
-
|
|
1276
|
-
trim: bool
|
|
1277
|
-
If True (default) return only the positive frequency values
|
|
1604
|
+
spectrum : NDArray
|
|
1605
|
+
Input spectrum array. Should contain non-negative values.
|
|
1278
1606
|
|
|
1279
1607
|
Returns
|
|
1280
1608
|
-------
|
|
1281
|
-
|
|
1282
|
-
|
|
1283
|
-
|
|
1284
|
-
|
|
1285
|
-
|
|
1286
|
-
|
|
1287
|
-
|
|
1288
|
-
|
|
1289
|
-
|
|
1290
|
-
|
|
1291
|
-
|
|
1292
|
-
|
|
1293
|
-
|
|
1294
|
-
|
|
1295
|
-
|
|
1609
|
+
float
|
|
1610
|
+
Spectral flatness value. Values close to 1.0 indicate a flat (white noise-like) spectrum,
|
|
1611
|
+
while values closer to 0.0 indicate a more tonal spectrum.
|
|
1612
|
+
|
|
1613
|
+
Notes
|
|
1614
|
+
-----
|
|
1615
|
+
The spectral flatness is computed as:
|
|
1616
|
+
flatness = exp(mean(log(spectrum))) / mean(spectrum)
|
|
1617
|
+
|
|
1618
|
+
This implementation assumes the input spectrum contains non-negative values.
|
|
1619
|
+
If the spectrum contains zeros, the geometric mean will be zero and the result
|
|
1620
|
+
will be zero regardless of the arithmetic mean.
|
|
1621
|
+
|
|
1622
|
+
Examples
|
|
1623
|
+
--------
|
|
1624
|
+
>>> import numpy as np
|
|
1625
|
+
>>> # White noise spectrum
|
|
1626
|
+
>>> white_noise = np.random.rand(100)
|
|
1627
|
+
>>> flatness = spectralflatness(white_noise)
|
|
1628
|
+
>>> # Tone-like spectrum
|
|
1629
|
+
>>> tone = np.zeros(100)
|
|
1630
|
+
>>> tone[50] = 1.0
|
|
1631
|
+
>>> flatness = spectralflatness(tone)
|
|
1296
1632
|
"""
|
|
1297
1633
|
if trim:
|
|
1298
1634
|
specvals = fftpack.fft(inputdata)[0 : len(inputdata) // 2]
|
|
@@ -1315,22 +1651,43 @@ def spectrum(inputdata, Fs=1.0, mode="power", trim=True):
|
|
|
1315
1651
|
elif mode == "power":
|
|
1316
1652
|
specvals = np.sqrt(np.absolute(specvals))
|
|
1317
1653
|
else:
|
|
1318
|
-
|
|
1319
|
-
specvals = None
|
|
1654
|
+
raise RuntimeError("illegal spectrum mode")
|
|
1320
1655
|
return specaxis, specvals
|
|
1321
1656
|
|
|
1322
1657
|
|
|
1323
|
-
def setnotchfilter(thefilter, thefreq, notchwidth=1.0):
|
|
1324
|
-
|
|
1658
|
+
def setnotchfilter(thefilter: object, thefreq: float, notchwidth: float = 1.0) -> None:
|
|
1659
|
+
"""
|
|
1660
|
+
Set notch filter parameters for the specified filter.
|
|
1661
|
+
|
|
1662
|
+
This function configures a notch filter by setting the filter type to "arb_stop"
|
|
1663
|
+
and defining the frequency range for the notch based on the center frequency
|
|
1664
|
+
and notch width parameters.
|
|
1325
1665
|
|
|
1326
1666
|
Parameters
|
|
1327
1667
|
----------
|
|
1328
|
-
thefilter: NoncausalFilter function
|
|
1329
|
-
The filter function to
|
|
1330
|
-
thefreq: float
|
|
1331
|
-
|
|
1332
|
-
notchwidth: float
|
|
1333
|
-
|
|
1668
|
+
thefilter : NoncausalFilter function
|
|
1669
|
+
The filter function to configure with notch filter parameters
|
|
1670
|
+
thefreq : float
|
|
1671
|
+
Center frequency of the notch in Hz
|
|
1672
|
+
notchwidth : float, optional
|
|
1673
|
+
Width of the notch in Hz, default is 1.0 Hz
|
|
1674
|
+
|
|
1675
|
+
Returns
|
|
1676
|
+
-------
|
|
1677
|
+
None
|
|
1678
|
+
This function modifies the filter in-place and does not return any value
|
|
1679
|
+
|
|
1680
|
+
Notes
|
|
1681
|
+
-----
|
|
1682
|
+
The notch filter is configured as an "arb_stop" type filter with symmetric
|
|
1683
|
+
frequency bounds around the center frequency. The actual notch range will be
|
|
1684
|
+
from (thefreq - notchwidth/2) to (thefreq + notchwidth/2) Hz.
|
|
1685
|
+
|
|
1686
|
+
Examples
|
|
1687
|
+
--------
|
|
1688
|
+
>>> filter_obj = NoncausalFilter()
|
|
1689
|
+
>>> setnotchfilter(filter_obj, 50.0, 2.0)
|
|
1690
|
+
>>> # Creates a notch filter centered at 50 Hz with 2 Hz width
|
|
1334
1691
|
"""
|
|
1335
1692
|
thefilter.settype("arb_stop")
|
|
1336
1693
|
thefilter.setfreqs(
|
|
@@ -1341,27 +1698,52 @@ def setnotchfilter(thefilter, thefreq, notchwidth=1.0):
|
|
|
1341
1698
|
)
|
|
1342
1699
|
|
|
1343
1700
|
|
|
1344
|
-
def harmonicnotchfilter(
|
|
1345
|
-
|
|
1701
|
+
def harmonicnotchfilter(
|
|
1702
|
+
timecourse: NDArray,
|
|
1703
|
+
Fs: float,
|
|
1704
|
+
Ffundamental: float,
|
|
1705
|
+
notchpct: float = 1.0,
|
|
1706
|
+
debug: bool = False,
|
|
1707
|
+
) -> NDArray:
|
|
1708
|
+
"""
|
|
1709
|
+
Apply a harmonic notch filter to remove a fundamental frequency and its harmonics from a timecourse.
|
|
1710
|
+
|
|
1711
|
+
This function removes the specified fundamental frequency and all its integer harmonics
|
|
1712
|
+
using a non-causal notch filtering approach. The width of each notch is proportional
|
|
1713
|
+
to the harmonic order and the specified percentage (`notchpct`).
|
|
1346
1714
|
|
|
1347
1715
|
Parameters
|
|
1348
1716
|
----------
|
|
1349
|
-
timecourse:
|
|
1350
|
-
Input data
|
|
1351
|
-
Fs: float
|
|
1352
|
-
|
|
1353
|
-
Ffundamental: float
|
|
1354
|
-
Fundamental frequency to be removed from the data
|
|
1355
|
-
notchpct: float, optional
|
|
1356
|
-
Width of the notch relative to the filter frequency in percent.
|
|
1357
|
-
debug: bool, optional
|
|
1358
|
-
|
|
1717
|
+
timecourse : NDArray
|
|
1718
|
+
Input timecourse data to be filtered.
|
|
1719
|
+
Fs : float
|
|
1720
|
+
Sampling rate of the input data in Hz.
|
|
1721
|
+
Ffundamental : float
|
|
1722
|
+
Fundamental frequency to be removed from the data in Hz.
|
|
1723
|
+
notchpct : float, optional
|
|
1724
|
+
Width of the notch relative to the filter frequency in percent. Default is 1.0.
|
|
1725
|
+
debug : bool, optional
|
|
1726
|
+
If True, prints detailed information about the filtering process. Default is False.
|
|
1359
1727
|
|
|
1360
1728
|
Returns
|
|
1361
1729
|
-------
|
|
1362
|
-
filteredtc:
|
|
1363
|
-
The filtered
|
|
1364
|
-
|
|
1730
|
+
filteredtc : NDArray
|
|
1731
|
+
The filtered timecourse with the fundamental and its harmonics removed.
|
|
1732
|
+
|
|
1733
|
+
Notes
|
|
1734
|
+
-----
|
|
1735
|
+
- The function uses a non-causal filter, meaning it requires the full signal to be available.
|
|
1736
|
+
- Harmonics are calculated as integer multiples of the fundamental frequency.
|
|
1737
|
+
- The notch width is determined by `notchpct * harmonic * Ffundamental * 0.01`, with a minimum
|
|
1738
|
+
width of one frequency bin.
|
|
1739
|
+
|
|
1740
|
+
Examples
|
|
1741
|
+
--------
|
|
1742
|
+
>>> import numpy as np
|
|
1743
|
+
>>> timecourse = np.random.randn(1000)
|
|
1744
|
+
>>> Fs = 100.0
|
|
1745
|
+
>>> Ffundamental = 50.0
|
|
1746
|
+
>>> filtered = harmonicnotchfilter(timecourse, Fs, Ffundamental, notchpct=2.0)
|
|
1365
1747
|
"""
|
|
1366
1748
|
# delete the fundamental and its harmonics
|
|
1367
1749
|
filteredtc = timecourse + 0.0
|
|
@@ -1393,44 +1775,100 @@ def harmonicnotchfilter(timecourse, Fs, Ffundamental, notchpct=1.0, debug=False)
|
|
|
1393
1775
|
return filteredtc
|
|
1394
1776
|
|
|
1395
1777
|
|
|
1396
|
-
def savgolsmooth(data, smoothlen=101, polyorder=3):
|
|
1397
|
-
|
|
1398
|
-
|
|
1778
|
+
def savgolsmooth(data: NDArray, smoothlen: int = 101, polyorder: int = 3) -> NDArray:
|
|
1779
|
+
"""
|
|
1780
|
+
Apply Savitzky-Golay filter to smooth data.
|
|
1399
1781
|
|
|
1400
|
-
|
|
1401
|
-
|
|
1402
|
-
|
|
1403
|
-
r"""Cross spectral density filter - makes a filter transfer function that preserves common frequencies.
|
|
1782
|
+
This function applies a Savitzky-Golay filter to smooth the input data. The filter uses
|
|
1783
|
+
a least-squares method to fit a polynomial to a sliding window of data points and
|
|
1784
|
+
replaces each point with the value of the polynomial at that point.
|
|
1404
1785
|
|
|
1405
1786
|
Parameters
|
|
1406
1787
|
----------
|
|
1407
|
-
|
|
1408
|
-
Input data
|
|
1788
|
+
data : array_like
|
|
1789
|
+
Input data to be smoothed. Can be any array-like object that can be converted
|
|
1790
|
+
to a numpy array.
|
|
1791
|
+
smoothlen : int, optional
|
|
1792
|
+
The length of the filter window (i.e., the number of coefficients). Must be a
|
|
1793
|
+
positive odd integer. Default is 101.
|
|
1794
|
+
polyorder : int, optional
|
|
1795
|
+
The order of the polynomial used to fit the samples. Must be less than
|
|
1796
|
+
`smoothlen`. Default is 3.
|
|
1409
1797
|
|
|
1410
|
-
|
|
1411
|
-
|
|
1798
|
+
Returns
|
|
1799
|
+
-------
|
|
1800
|
+
NDArray
|
|
1801
|
+
The smoothed data with the same shape as the input `data`.
|
|
1802
|
+
|
|
1803
|
+
Notes
|
|
1804
|
+
-----
|
|
1805
|
+
The Savitzky-Golay filter is particularly useful for smoothing noisy data while
|
|
1806
|
+
preserving the shape and features of the underlying signal. It is especially
|
|
1807
|
+
effective for data with a lot of high-frequency noise.
|
|
1808
|
+
|
|
1809
|
+
Examples
|
|
1810
|
+
--------
|
|
1811
|
+
>>> import numpy as np
|
|
1812
|
+
>>> from scipy.signal import savgol_filter
|
|
1813
|
+
>>> x = np.linspace(0, 4*np.pi, 100)
|
|
1814
|
+
>>> y = np.sin(x) + np.random.normal(0, 0.1, 100)
|
|
1815
|
+
>>> y_smooth = savgolsmooth(y, smoothlen=21, polyorder=3)
|
|
1816
|
+
"""
|
|
1817
|
+
return savgol_filter(data, smoothlen, polyorder)
|
|
1412
1818
|
|
|
1413
|
-
padlen: int, optional
|
|
1414
|
-
Number of reflected points to add on each end of the input data. Default is 20.
|
|
1415
1819
|
|
|
1416
|
-
|
|
1417
|
-
|
|
1820
|
+
def csdfilter(
|
|
1821
|
+
obsdata: NDArray,
|
|
1822
|
+
commondata: NDArray,
|
|
1823
|
+
padlen: int = 20,
|
|
1824
|
+
avlen: int = 20,
|
|
1825
|
+
padtype: str = "reflect",
|
|
1826
|
+
debug: bool = False,
|
|
1827
|
+
) -> NDArray:
|
|
1828
|
+
"""
|
|
1829
|
+
Cross spectral density filter - makes a filter transfer function that preserves common frequencies.
|
|
1418
1830
|
|
|
1419
|
-
|
|
1420
|
-
|
|
1831
|
+
This function applies a filter based on the cross spectral density between two signals.
|
|
1832
|
+
It uses the Fourier transform to compute the transfer function and applies it to the
|
|
1833
|
+
observation data, preserving the frequency components that are common between the two
|
|
1834
|
+
input signals.
|
|
1835
|
+
|
|
1836
|
+
Parameters
|
|
1837
|
+
----------
|
|
1838
|
+
obsdata : NDArray
|
|
1839
|
+
Input data (1D numpy array) to be filtered.
|
|
1840
|
+
commondata : NDArray
|
|
1841
|
+
Shared data (1D numpy array) used to compute the transfer function.
|
|
1842
|
+
padlen : int, optional
|
|
1843
|
+
Number of reflected points to add on each end of the input data. Default is 20.
|
|
1844
|
+
avlen : int, optional
|
|
1845
|
+
Length of the averaging window for padding. Default is 20.
|
|
1846
|
+
padtype : str, optional
|
|
1847
|
+
Type of padding to use. Options are 'reflect' or 'cyclic'. Default is 'reflect'.
|
|
1848
|
+
debug : bool, optional
|
|
1849
|
+
Set to True for additional information on function internals. Default is False.
|
|
1421
1850
|
|
|
1422
1851
|
Returns
|
|
1423
1852
|
-------
|
|
1424
|
-
|
|
1425
|
-
The filtered data
|
|
1426
|
-
|
|
1853
|
+
NDArray
|
|
1854
|
+
The filtered data (1D numpy array) with preserved common frequencies.
|
|
1855
|
+
|
|
1856
|
+
Notes
|
|
1857
|
+
-----
|
|
1858
|
+
The function first pads both input arrays using the specified padding method, then computes
|
|
1859
|
+
the FFT of both padded arrays. A transfer function is constructed from the square root of
|
|
1860
|
+
the magnitude of the product of the FFTs. This transfer function is applied to the FFT of
|
|
1861
|
+
the observation data, and the inverse FFT is taken to return the filtered signal.
|
|
1862
|
+
|
|
1863
|
+
Examples
|
|
1864
|
+
--------
|
|
1865
|
+
>>> import numpy as np
|
|
1866
|
+
>>> obs = np.random.randn(100)
|
|
1867
|
+
>>> common = np.random.randn(100)
|
|
1868
|
+
>>> filtered = csdfilter(obs, common, padlen=10)
|
|
1427
1869
|
"""
|
|
1428
|
-
padobsdata = padvec(
|
|
1429
|
-
|
|
1430
|
-
)
|
|
1431
|
-
padcommondata = padvec(
|
|
1432
|
-
commondata, padlen=padlen, avlen=avlen, padtype=padtype, debug=debug
|
|
1433
|
-
)
|
|
1870
|
+
padobsdata = padvec(obsdata, padlen=padlen, avlen=avlen, padtype=padtype, debug=debug)
|
|
1871
|
+
padcommondata = padvec(commondata, padlen=padlen, avlen=avlen, padtype=padtype, debug=debug)
|
|
1434
1872
|
obsdata_trans = fftpack.fft(padobsdata)
|
|
1435
1873
|
transferfunc = np.sqrt(np.abs(fftpack.fft(padobsdata) * np.conj(fftpack.fft(padcommondata))))
|
|
1436
1874
|
obsdata_trans *= transferfunc
|
|
@@ -1439,69 +1877,88 @@ def csdfilter(
|
|
|
1439
1877
|
|
|
1440
1878
|
# @conditionaljit()
|
|
1441
1879
|
def arb_pass(
|
|
1442
|
-
Fs,
|
|
1443
|
-
inputdata,
|
|
1444
|
-
lowerstop,
|
|
1445
|
-
lowerpass,
|
|
1446
|
-
upperpass,
|
|
1447
|
-
upperstop,
|
|
1448
|
-
transferfunc="trapezoidal",
|
|
1449
|
-
butterorder=6,
|
|
1450
|
-
padlen=20,
|
|
1451
|
-
avlen=20,
|
|
1452
|
-
padtype="reflect",
|
|
1453
|
-
debug=False,
|
|
1454
|
-
):
|
|
1455
|
-
|
|
1456
|
-
|
|
1457
|
-
|
|
1880
|
+
Fs: float,
|
|
1881
|
+
inputdata: NDArray,
|
|
1882
|
+
lowerstop: float,
|
|
1883
|
+
lowerpass: float,
|
|
1884
|
+
upperpass: float,
|
|
1885
|
+
upperstop: float,
|
|
1886
|
+
transferfunc: str = "trapezoidal",
|
|
1887
|
+
butterorder: int = 6,
|
|
1888
|
+
padlen: int = 20,
|
|
1889
|
+
avlen: int = 20,
|
|
1890
|
+
padtype: str = "reflect",
|
|
1891
|
+
debug: bool = False,
|
|
1892
|
+
) -> NDArray:
|
|
1893
|
+
"""
|
|
1894
|
+
Filters an input waveform over a specified range using configurable filter types.
|
|
1895
|
+
|
|
1896
|
+
By default, it applies a trapezoidal FFT filter, but brickwall and Butterworth
|
|
1897
|
+
filters are also supported. The function handles lowpass, bandpass, and highpass
|
|
1898
|
+
filtering based on the input frequency limits. Ends of the input data are padded
|
|
1899
|
+
to reduce transients.
|
|
1458
1900
|
|
|
1459
1901
|
Parameters
|
|
1460
1902
|
----------
|
|
1461
1903
|
Fs : float
|
|
1462
|
-
Sample rate in Hz
|
|
1463
|
-
|
|
1464
|
-
|
|
1465
|
-
inputdata : 1D numpy array
|
|
1466
|
-
Input data to be filtered
|
|
1467
|
-
:param inputdata:
|
|
1468
|
-
|
|
1904
|
+
Sample rate in Hz.
|
|
1905
|
+
inputdata : NDArray
|
|
1906
|
+
Input data to be filtered.
|
|
1469
1907
|
lowerstop : float
|
|
1470
|
-
Upper end of lower stopband in Hz
|
|
1471
|
-
:param lowerstop:
|
|
1472
|
-
|
|
1908
|
+
Upper end of lower stopband in Hz.
|
|
1473
1909
|
lowerpass : float
|
|
1474
|
-
Lower end of passband in Hz
|
|
1475
|
-
:param lowerpass:
|
|
1476
|
-
|
|
1910
|
+
Lower end of passband in Hz.
|
|
1477
1911
|
upperpass : float
|
|
1478
|
-
Upper end of passband in Hz
|
|
1479
|
-
:param upperpass:
|
|
1480
|
-
|
|
1912
|
+
Upper end of passband in Hz.
|
|
1481
1913
|
upperstop : float
|
|
1482
|
-
Lower end of upper stopband in Hz
|
|
1483
|
-
|
|
1484
|
-
|
|
1914
|
+
Lower end of upper stopband in Hz.
|
|
1915
|
+
transferfunc : str, optional
|
|
1916
|
+
Type of transfer function to use. Options are:
|
|
1917
|
+
- "trapezoidal" (default)
|
|
1918
|
+
- "brickwall"
|
|
1919
|
+
- "butterworth"
|
|
1485
1920
|
butterorder : int, optional
|
|
1486
|
-
Order of Butterworth filter, if used.
|
|
1487
|
-
:param butterorder:
|
|
1488
|
-
|
|
1921
|
+
Order of Butterworth filter, if used. Default is 6.
|
|
1489
1922
|
padlen : int, optional
|
|
1490
|
-
Amount of points to reflect around each end of the input vector prior to filtering.
|
|
1491
|
-
|
|
1492
|
-
|
|
1493
|
-
|
|
1494
|
-
|
|
1495
|
-
|
|
1496
|
-
|
|
1497
|
-
|
|
1498
|
-
|
|
1499
|
-
|
|
1923
|
+
Amount of points to reflect around each end of the input vector prior to filtering.
|
|
1924
|
+
Default is 20.
|
|
1925
|
+
avlen : int, optional
|
|
1926
|
+
Length of averaging window for filtering. Default is 20.
|
|
1927
|
+
padtype : str, optional
|
|
1928
|
+
Padding type for end effects. Options are:
|
|
1929
|
+
- "reflect" (default)
|
|
1930
|
+
- "wrap"
|
|
1931
|
+
debug : bool, optional
|
|
1932
|
+
If True, internal states of the function will be printed to help debugging.
|
|
1933
|
+
Default is False.
|
|
1500
1934
|
|
|
1501
1935
|
Returns
|
|
1502
1936
|
-------
|
|
1503
|
-
filtereddata :
|
|
1504
|
-
The filtered data
|
|
1937
|
+
filtereddata : NDArray
|
|
1938
|
+
The filtered data as a 1D float array.
|
|
1939
|
+
|
|
1940
|
+
Notes
|
|
1941
|
+
-----
|
|
1942
|
+
The function automatically determines whether to apply a lowpass, highpass, or
|
|
1943
|
+
bandpass filter based on the values of `lowerpass` and `upperpass`. For bandpass
|
|
1944
|
+
filters, a cascade of lowpass and highpass Butterworth filters is used when
|
|
1945
|
+
`transferfunc="butterworth"`.
|
|
1946
|
+
|
|
1947
|
+
Examples
|
|
1948
|
+
--------
|
|
1949
|
+
>>> import numpy as np
|
|
1950
|
+
>>> Fs = 100.0
|
|
1951
|
+
>>> t = np.linspace(0, 1, int(Fs), endpoint=False)
|
|
1952
|
+
>>> signal = np.sin(2 * np.pi * 10 * t) + 0.5 * np.sin(2 * np.pi * 20 * t)
|
|
1953
|
+
>>> filtered = arb_pass(
|
|
1954
|
+
... Fs=Fs,
|
|
1955
|
+
... inputdata=signal,
|
|
1956
|
+
... lowerstop=5.0,
|
|
1957
|
+
... lowerpass=8.0,
|
|
1958
|
+
... upperpass=15.0,
|
|
1959
|
+
... upperstop=20.0,
|
|
1960
|
+
... transferfunc="trapezoidal"
|
|
1961
|
+
... )
|
|
1505
1962
|
"""
|
|
1506
1963
|
# check filter limits to see if we should do a lowpass, bandpass, or highpass
|
|
1507
1964
|
if lowerpass <= 0.0:
|
|
@@ -1547,8 +2004,8 @@ def arb_pass(
|
|
|
1547
2004
|
return dohptransfuncfilt(
|
|
1548
2005
|
Fs,
|
|
1549
2006
|
inputdata,
|
|
2007
|
+
lowerpass,
|
|
1550
2008
|
lowerstop=lowerstop,
|
|
1551
|
-
lowerpass=lowerpass,
|
|
1552
2009
|
type=transferfunc,
|
|
1553
2010
|
padlen=padlen,
|
|
1554
2011
|
avlen=avlen,
|
|
@@ -1581,9 +2038,9 @@ def arb_pass(
|
|
|
1581
2038
|
return dobptransfuncfilt(
|
|
1582
2039
|
Fs,
|
|
1583
2040
|
inputdata,
|
|
2041
|
+
lowerpass,
|
|
2042
|
+
upperpass,
|
|
1584
2043
|
lowerstop=lowerstop,
|
|
1585
|
-
lowerpass=lowerpass,
|
|
1586
|
-
upperpass=upperpass,
|
|
1587
2044
|
upperstop=upperstop,
|
|
1588
2045
|
type=transferfunc,
|
|
1589
2046
|
padlen=padlen,
|
|
@@ -1595,6 +2052,39 @@ def arb_pass(
|
|
|
1595
2052
|
|
|
1596
2053
|
class Plethfilter:
|
|
1597
2054
|
def __init_(self, Fs, Fl, Fh, order=4, attenuation=20):
|
|
2055
|
+
"""
|
|
2056
|
+
Initialize Chebyshev type II bandpass filter.
|
|
2057
|
+
|
|
2058
|
+
Parameters
|
|
2059
|
+
----------
|
|
2060
|
+
Fs : float
|
|
2061
|
+
Sampling frequency in Hz.
|
|
2062
|
+
Fl : float
|
|
2063
|
+
Lower cutoff frequency in Hz.
|
|
2064
|
+
Fh : float
|
|
2065
|
+
Higher cutoff frequency in Hz.
|
|
2066
|
+
order : int, optional
|
|
2067
|
+
Filter order (default is 4).
|
|
2068
|
+
attenuation : float, optional
|
|
2069
|
+
Stopband attenuation in dB (default is 20).
|
|
2070
|
+
|
|
2071
|
+
Returns
|
|
2072
|
+
-------
|
|
2073
|
+
None
|
|
2074
|
+
Initializes filter coefficients and parameters.
|
|
2075
|
+
|
|
2076
|
+
Notes
|
|
2077
|
+
-----
|
|
2078
|
+
This function creates a Chebyshev type II bandpass filter using scipy.signal.cheby2.
|
|
2079
|
+
The filter has a flat response in the passband and an equiripple response in the stopband.
|
|
2080
|
+
The filter coefficients are stored in self.b and self.a for subsequent filtering operations.
|
|
2081
|
+
|
|
2082
|
+
Examples
|
|
2083
|
+
--------
|
|
2084
|
+
>>> filter = BandpassFilter(Fs=1000, Fl=100, Fh=300, order=6, attenuation=30)
|
|
2085
|
+
>>> print(filter.b) # Print filter numerator coefficients
|
|
2086
|
+
>>> print(filter.a) # Print filter denominator coefficients
|
|
2087
|
+
"""
|
|
1598
2088
|
self.Fs = Fs
|
|
1599
2089
|
self.Fh = Fh
|
|
1600
2090
|
self.Fl = Fl
|
|
@@ -1615,7 +2105,40 @@ class Plethfilter:
|
|
|
1615
2105
|
return signal.filtfilt(self.b, self.a, data, axis=-1, padtype="odd", padlen=None)
|
|
1616
2106
|
|
|
1617
2107
|
|
|
1618
|
-
def getfilterbandfreqs(
|
|
2108
|
+
def getfilterbandfreqs(
|
|
2109
|
+
band: str, transitionfrac: float = 0.05, species: str = "human", asrange: bool = False
|
|
2110
|
+
) -> Union[str, Tuple[float, float, float, float]]:
|
|
2111
|
+
"""
|
|
2112
|
+
Apply digital filter forward and backward to data.
|
|
2113
|
+
|
|
2114
|
+
This function applies a digital filter to the input data using forward-backward filtering
|
|
2115
|
+
to eliminate phase distortion. The filter is applied along the last axis of the data.
|
|
2116
|
+
|
|
2117
|
+
Parameters
|
|
2118
|
+
----------
|
|
2119
|
+
data : array_like
|
|
2120
|
+
Input data to be filtered. Can be any shape, but filtering is applied along the
|
|
2121
|
+
last axis (axis=-1).
|
|
2122
|
+
|
|
2123
|
+
Returns
|
|
2124
|
+
-------
|
|
2125
|
+
NDArray
|
|
2126
|
+
The filtered output with the same shape as the input data.
|
|
2127
|
+
|
|
2128
|
+
Notes
|
|
2129
|
+
-----
|
|
2130
|
+
This function uses `scipy.signal.filtfilt` which applies the filter forward and backward
|
|
2131
|
+
to eliminate phase distortion. The filter coefficients are stored in `self.b` and `self.a`.
|
|
2132
|
+
|
|
2133
|
+
Examples
|
|
2134
|
+
--------
|
|
2135
|
+
>>> import numpy as np
|
|
2136
|
+
>>> from scipy import signal
|
|
2137
|
+
>>> # Create a simple filter
|
|
2138
|
+
>>> b, a = signal.butter(4, 0.2, 'low')
|
|
2139
|
+
>>> # Apply filter to data
|
|
2140
|
+
>>> filtered_data = apply(data)
|
|
2141
|
+
"""
|
|
1619
2142
|
if species == "human":
|
|
1620
2143
|
if band == "vlf":
|
|
1621
2144
|
lowerpass = 0.0
|
|
@@ -1700,46 +2223,63 @@ class NoncausalFilter:
|
|
|
1700
2223
|
padtype="reflect",
|
|
1701
2224
|
debug=False,
|
|
1702
2225
|
):
|
|
1703
|
-
|
|
2226
|
+
"""
|
|
2227
|
+
Initialize a zero time delay filter for one-dimensional signals, especially physiological ones.
|
|
2228
|
+
|
|
2229
|
+
This constructor sets up the filter parameters and initializes the filter type.
|
|
2230
|
+
The filter can be configured for various physiological signal processing tasks,
|
|
2231
|
+
including VLF, LFO, respiratory, cardiac, and HRV-related filtering.
|
|
1704
2232
|
|
|
1705
2233
|
Parameters
|
|
1706
2234
|
----------
|
|
1707
|
-
filtertype : {'None' 'vlf', 'lfo', 'resp', 'cardiac', 'vlf_stop', 'lfo_stop', 'resp_stop', 'card_stop',
|
|
1708
|
-
|
|
1709
|
-
|
|
1710
|
-
|
|
1711
|
-
|
|
1712
|
-
|
|
1713
|
-
|
|
1714
|
-
|
|
1715
|
-
|
|
1716
|
-
|
|
1717
|
-
|
|
1718
|
-
|
|
1719
|
-
|
|
1720
|
-
|
|
2235
|
+
filtertype : {'None', 'vlf', 'lfo', 'resp', 'cardiac', 'vlf_stop', 'lfo_stop', 'resp_stop', 'card_stop',
|
|
2236
|
+
'hrv_ulf', 'hrv_vlf', 'hrv_lf', 'hrv_hf', 'hrv_vhf', 'hrv_ulf_stop', 'hrv_vlf_stop',
|
|
2237
|
+
'hrv_lf_stop', 'hrv_hf_stop', 'hrv_vhf_stop', 'arb', 'arb_stop', 'ringstop'}, optional
|
|
2238
|
+
The type of filter to apply. Default is 'None'.
|
|
2239
|
+
transitionfrac : float, optional
|
|
2240
|
+
Fraction of the transition band used for filter transition. Default is 0.05.
|
|
2241
|
+
transferfunc : {'trapezoidal', 'butterworth'}, optional
|
|
2242
|
+
Transfer function to use for filter design. Default is 'trapezoidal'.
|
|
2243
|
+
initlowerstop : float, optional
|
|
2244
|
+
Initial lower stop frequency for 'arb' and 'arb_stop' filters. Default is None.
|
|
2245
|
+
initlowerpass : float, optional
|
|
2246
|
+
Initial lower pass frequency for 'arb' and 'arb_stop' filters. Default is None.
|
|
2247
|
+
initupperpass : float, optional
|
|
2248
|
+
Initial upper pass frequency for 'arb' and 'arb_stop' filters. Default is None.
|
|
2249
|
+
initupperstop : float, optional
|
|
2250
|
+
Initial upper stop frequency for 'arb' and 'arb_stop' filters. Default is None.
|
|
2251
|
+
butterworthorder : int, optional
|
|
2252
|
+
Order of the Butterworth filter. Default is 6.
|
|
2253
|
+
correctfreq : bool, optional
|
|
2254
|
+
Whether to correct impossible pass frequencies. Default is True.
|
|
2255
|
+
padtime : float, optional
|
|
2256
|
+
Amount of time (in seconds) to pad the signal to reduce edge effects. Default is 30.0.
|
|
2257
|
+
padtype : {'reflect', 'zero', 'constant'}, optional
|
|
2258
|
+
Type of padding to use. Default is 'reflect'.
|
|
2259
|
+
debug : bool, optional
|
|
2260
|
+
Enable extended debugging messages. Default is False.
|
|
2261
|
+
|
|
2262
|
+
Returns
|
|
1721
2263
|
-------
|
|
1722
|
-
|
|
1723
|
-
|
|
1724
|
-
|
|
1725
|
-
|
|
1726
|
-
|
|
1727
|
-
|
|
1728
|
-
|
|
1729
|
-
|
|
1730
|
-
|
|
1731
|
-
|
|
1732
|
-
|
|
1733
|
-
|
|
1734
|
-
|
|
1735
|
-
|
|
1736
|
-
|
|
1737
|
-
|
|
1738
|
-
|
|
1739
|
-
|
|
1740
|
-
|
|
1741
|
-
setfreqs(lowerstop, lowerpass, upperpass, upperstop)
|
|
1742
|
-
Set the frequency parameters of the 'arb' and 'arb_stop' filter.
|
|
2264
|
+
None
|
|
2265
|
+
This method initializes the instance and does not return any value.
|
|
2266
|
+
|
|
2267
|
+
Notes
|
|
2268
|
+
-----
|
|
2269
|
+
For 'arb' and 'arb_stop' filter types, the pass and stop frequencies are initialized
|
|
2270
|
+
based on the provided values or default values if not specified.
|
|
2271
|
+
The default frequencies for 'arb' filters are:
|
|
2272
|
+
- lowerpass = 0.05 Hz
|
|
2273
|
+
- lowerstop = 0.9 * lowerpass
|
|
2274
|
+
- upperpass = 0.20 Hz
|
|
2275
|
+
- upperstop = 1.1 * upperpass
|
|
2276
|
+
|
|
2277
|
+
Examples
|
|
2278
|
+
--------
|
|
2279
|
+
>>> filter_instance = ZeroDelayFilter(filtertype='resp', padtime=60.0)
|
|
2280
|
+
>>> filter_instance.settype('cardiac')
|
|
2281
|
+
>>> filter_instance.gettype()
|
|
2282
|
+
'cardiac'
|
|
1743
2283
|
"""
|
|
1744
2284
|
self.filtertype = filtertype
|
|
1745
2285
|
self.species = "human"
|
|
@@ -1770,6 +2310,50 @@ class NoncausalFilter:
|
|
|
1770
2310
|
self.settype(self.filtertype)
|
|
1771
2311
|
|
|
1772
2312
|
def settype(self, thetype):
|
|
2313
|
+
"""
|
|
2314
|
+
Set the filter type and corresponding frequency bands for the filter object.
|
|
2315
|
+
|
|
2316
|
+
This method configures the filter parameters based on the specified filter type.
|
|
2317
|
+
It assigns passband and stopband frequencies depending on the filter type,
|
|
2318
|
+
using predefined frequency ranges or user-defined values for arbitrary filters.
|
|
2319
|
+
|
|
2320
|
+
Parameters
|
|
2321
|
+
----------
|
|
2322
|
+
thetype : str
|
|
2323
|
+
The type of filter to set. Supported values include:
|
|
2324
|
+
- "vlf", "vlf_stop": Very Low Frequency
|
|
2325
|
+
- "lfo", "lfo_stop": Low Frequency Oscillation
|
|
2326
|
+
- "lfo_legacy", "lfo_legacy_stop": Legacy Low Frequency Oscillation
|
|
2327
|
+
- "lfo_tight", "lfo_tight_stop": Tight Low Frequency Oscillation
|
|
2328
|
+
- "resp", "resp_stop": Respiration
|
|
2329
|
+
- "cardiac", "cardiac_stop": Cardiac
|
|
2330
|
+
- "hrv_ulf", "hrv_ulf_stop": HRV Ultra Low Frequency
|
|
2331
|
+
- "hrv_vlf", "hrv_vlf_stop": HRV Very Low Frequency
|
|
2332
|
+
- "hrv_lf", "hrv_lf_stop": HRV Low Frequency
|
|
2333
|
+
- "hrv_hf", "hrv_hf_stop": HRV High Frequency
|
|
2334
|
+
- "hrv_vhf", "hrv_vhf_stop": HRV Very High Frequency
|
|
2335
|
+
- "arb", "arb_stop": Arbitrary filter with custom frequency limits
|
|
2336
|
+
|
|
2337
|
+
Notes
|
|
2338
|
+
-----
|
|
2339
|
+
For arbitrary filters ("arb" or "arb_stop"), the method uses the following
|
|
2340
|
+
attributes from the object:
|
|
2341
|
+
- `self.arb_lowerstop`
|
|
2342
|
+
- `self.arb_lowerpass`
|
|
2343
|
+
- `self.arb_upperpass`
|
|
2344
|
+
- `self.arb_upperstop`
|
|
2345
|
+
|
|
2346
|
+
For all other filter types, the method calls `getfilterbandfreqs` with the
|
|
2347
|
+
specified filter type and additional parameters like `transitionfrac` and `species`.
|
|
2348
|
+
|
|
2349
|
+
Examples
|
|
2350
|
+
--------
|
|
2351
|
+
>>> obj.settype("lfo")
|
|
2352
|
+
>>> print(obj.lowerpass)
|
|
2353
|
+
0.01
|
|
2354
|
+
>>> print(obj.upperstop)
|
|
2355
|
+
0.5
|
|
2356
|
+
"""
|
|
1773
2357
|
self.filtertype = thetype
|
|
1774
2358
|
if self.filtertype == "vlf" or self.filtertype == "vlf_stop":
|
|
1775
2359
|
self.lowerpass, self.upperpass, self.lowerstop, self.upperstop = getfilterbandfreqs(
|
|
@@ -1827,30 +2411,272 @@ class NoncausalFilter:
|
|
|
1827
2411
|
self.upperstop = 1.0e20
|
|
1828
2412
|
|
|
1829
2413
|
def gettype(self):
|
|
2414
|
+
"""
|
|
2415
|
+
Return the filter type of the object.
|
|
2416
|
+
|
|
2417
|
+
Returns
|
|
2418
|
+
-------
|
|
2419
|
+
filtertype : str or int
|
|
2420
|
+
The filter type associated with the object. The specific type depends
|
|
2421
|
+
on the implementation of the filtertype attribute.
|
|
2422
|
+
|
|
2423
|
+
Notes
|
|
2424
|
+
-----
|
|
2425
|
+
This method provides access to the internal filtertype attribute.
|
|
2426
|
+
The return value type may vary depending on the specific implementation
|
|
2427
|
+
of the class that contains this method.
|
|
2428
|
+
|
|
2429
|
+
Examples
|
|
2430
|
+
--------
|
|
2431
|
+
>>> obj = MyClass()
|
|
2432
|
+
>>> obj.gettype()
|
|
2433
|
+
'some_filter_type'
|
|
2434
|
+
"""
|
|
1830
2435
|
return self.filtertype
|
|
1831
2436
|
|
|
1832
2437
|
def setbutterorder(self, order=3):
|
|
2438
|
+
"""
|
|
2439
|
+
Set the Butterworth filter order for the system.
|
|
2440
|
+
|
|
2441
|
+
This method assigns the specified order to the Butterworth filter configuration.
|
|
2442
|
+
The order determines the steepness of the filter's roll-off characteristics.
|
|
2443
|
+
|
|
2444
|
+
Parameters
|
|
2445
|
+
----------
|
|
2446
|
+
order : int, optional
|
|
2447
|
+
The order of the Butterworth filter. Must be a positive integer.
|
|
2448
|
+
Default is 3.
|
|
2449
|
+
|
|
2450
|
+
Returns
|
|
2451
|
+
-------
|
|
2452
|
+
None
|
|
2453
|
+
This method does not return any value.
|
|
2454
|
+
|
|
2455
|
+
Notes
|
|
2456
|
+
-----
|
|
2457
|
+
A higher filter order results in a steeper roll-off but may introduce
|
|
2458
|
+
more phase distortion. The order should be chosen based on the specific
|
|
2459
|
+
requirements of the signal processing application.
|
|
2460
|
+
|
|
2461
|
+
Examples
|
|
2462
|
+
--------
|
|
2463
|
+
>>> system = SomeFilterClass()
|
|
2464
|
+
>>> system.setbutterorder(5)
|
|
2465
|
+
>>> print(system.butterworthorder)
|
|
2466
|
+
5
|
|
2467
|
+
|
|
2468
|
+
>>> system.setbutterorder()
|
|
2469
|
+
>>> print(system.butterworthorder)
|
|
2470
|
+
3
|
|
2471
|
+
"""
|
|
1833
2472
|
self.butterworthorder = order
|
|
1834
2473
|
|
|
1835
2474
|
def setdebug(self, debug):
|
|
2475
|
+
"""
|
|
2476
|
+
Set the debug flag for the object.
|
|
2477
|
+
|
|
2478
|
+
Parameters
|
|
2479
|
+
----------
|
|
2480
|
+
debug : bool
|
|
2481
|
+
If True, enables debug mode. If False, disables debug mode.
|
|
2482
|
+
|
|
2483
|
+
Returns
|
|
2484
|
+
-------
|
|
2485
|
+
None
|
|
2486
|
+
This method does not return any value.
|
|
2487
|
+
|
|
2488
|
+
Notes
|
|
2489
|
+
-----
|
|
2490
|
+
This method sets the internal `debug` attribute of the object. When debug mode
|
|
2491
|
+
is enabled, additional logging or verbose output may be generated during
|
|
2492
|
+
object operations.
|
|
2493
|
+
|
|
2494
|
+
Examples
|
|
2495
|
+
--------
|
|
2496
|
+
>>> obj = MyClass()
|
|
2497
|
+
>>> obj.setdebug(True)
|
|
2498
|
+
>>> print(obj.debug)
|
|
2499
|
+
True
|
|
2500
|
+
"""
|
|
1836
2501
|
self.debug = debug
|
|
1837
2502
|
|
|
1838
2503
|
def setpadtime(self, padtime):
|
|
2504
|
+
"""
|
|
2505
|
+
Set the padding time for the object.
|
|
2506
|
+
|
|
2507
|
+
Parameters
|
|
2508
|
+
----------
|
|
2509
|
+
padtime : float or int
|
|
2510
|
+
The padding time value to be assigned to the object's padtime attribute.
|
|
2511
|
+
|
|
2512
|
+
Returns
|
|
2513
|
+
-------
|
|
2514
|
+
None
|
|
2515
|
+
This method does not return any value.
|
|
2516
|
+
|
|
2517
|
+
Notes
|
|
2518
|
+
-----
|
|
2519
|
+
This method directly assigns the provided padtime value to the instance's padtime attribute,
|
|
2520
|
+
replacing any existing value.
|
|
2521
|
+
|
|
2522
|
+
Examples
|
|
2523
|
+
--------
|
|
2524
|
+
>>> obj = MyClass()
|
|
2525
|
+
>>> obj.setpadtime(5.0)
|
|
2526
|
+
>>> print(obj.padtime)
|
|
2527
|
+
5.0
|
|
2528
|
+
"""
|
|
1839
2529
|
self.padtime = padtime
|
|
1840
2530
|
|
|
1841
2531
|
def getpadtime(self):
|
|
2532
|
+
"""
|
|
2533
|
+
Return the padding time value.
|
|
2534
|
+
|
|
2535
|
+
Returns
|
|
2536
|
+
-------
|
|
2537
|
+
padtime : float or int
|
|
2538
|
+
The padding time value stored in the instance variable `self.padtime`.
|
|
2539
|
+
|
|
2540
|
+
Notes
|
|
2541
|
+
-----
|
|
2542
|
+
This is a simple getter method that returns the value of the internal
|
|
2543
|
+
`padtime` attribute. The actual meaning and units of this value depend
|
|
2544
|
+
on the context in which the class is used.
|
|
2545
|
+
|
|
2546
|
+
Examples
|
|
2547
|
+
--------
|
|
2548
|
+
>>> obj = MyClass()
|
|
2549
|
+
>>> obj.padtime = 5.0
|
|
2550
|
+
>>> obj.getpadtime()
|
|
2551
|
+
5.0
|
|
2552
|
+
"""
|
|
1842
2553
|
return self.padtime
|
|
1843
2554
|
|
|
1844
2555
|
def setpadtype(self, padtype):
|
|
2556
|
+
"""
|
|
2557
|
+
Set the padding type for the object.
|
|
2558
|
+
|
|
2559
|
+
Parameters
|
|
2560
|
+
----------
|
|
2561
|
+
padtype : str
|
|
2562
|
+
The padding type to be set. This parameter determines how padding
|
|
2563
|
+
will be applied in subsequent operations.
|
|
2564
|
+
|
|
2565
|
+
Returns
|
|
2566
|
+
-------
|
|
2567
|
+
None
|
|
2568
|
+
This method does not return any value.
|
|
2569
|
+
|
|
2570
|
+
Notes
|
|
2571
|
+
-----
|
|
2572
|
+
This method directly assigns the provided padding type to the internal
|
|
2573
|
+
`padtype` attribute of the object. The valid values for `padtype` depend
|
|
2574
|
+
on the specific implementation of the class this method belongs to.
|
|
2575
|
+
|
|
2576
|
+
Examples
|
|
2577
|
+
--------
|
|
2578
|
+
>>> obj = MyClass()
|
|
2579
|
+
>>> obj.setpadtype('constant')
|
|
2580
|
+
>>> print(obj.padtype)
|
|
2581
|
+
'constant'
|
|
2582
|
+
"""
|
|
1845
2583
|
self.padtype = padtype
|
|
1846
2584
|
|
|
1847
2585
|
def getpadtype(self):
|
|
2586
|
+
"""
|
|
2587
|
+
Return the padding type of the object.
|
|
2588
|
+
|
|
2589
|
+
Returns
|
|
2590
|
+
-------
|
|
2591
|
+
str
|
|
2592
|
+
The padding type as a string identifier.
|
|
2593
|
+
|
|
2594
|
+
Notes
|
|
2595
|
+
-----
|
|
2596
|
+
This method provides access to the internal `padtype` attribute
|
|
2597
|
+
which defines the padding behavior for the object.
|
|
2598
|
+
|
|
2599
|
+
Examples
|
|
2600
|
+
--------
|
|
2601
|
+
>>> obj = MyClass()
|
|
2602
|
+
>>> obj.padtype = 'constant'
|
|
2603
|
+
>>> obj.getpadtype()
|
|
2604
|
+
'constant'
|
|
2605
|
+
"""
|
|
1848
2606
|
return self.padtype
|
|
1849
2607
|
|
|
1850
2608
|
def settransferfunc(self, transferfunc):
|
|
2609
|
+
"""
|
|
2610
|
+
Set the transfer function for the system.
|
|
2611
|
+
|
|
2612
|
+
Parameters
|
|
2613
|
+
----------
|
|
2614
|
+
transferfunc : callable
|
|
2615
|
+
The transfer function to be assigned to the system. This should be a
|
|
2616
|
+
callable object that defines the system's transfer function behavior.
|
|
2617
|
+
|
|
2618
|
+
Returns
|
|
2619
|
+
-------
|
|
2620
|
+
None
|
|
2621
|
+
This method does not return any value.
|
|
2622
|
+
|
|
2623
|
+
Notes
|
|
2624
|
+
-----
|
|
2625
|
+
This method directly assigns the provided transfer function to the
|
|
2626
|
+
internal `transferfunc` attribute of the object. The transfer function
|
|
2627
|
+
should be compatible with the system's expected input and output formats.
|
|
2628
|
+
|
|
2629
|
+
Examples
|
|
2630
|
+
--------
|
|
2631
|
+
>>> system = MySystem()
|
|
2632
|
+
>>> def my_transfer_func(x):
|
|
2633
|
+
... return x * 2
|
|
2634
|
+
>>> system.settransferfunc(my_transfer_func)
|
|
2635
|
+
>>> system.transferfunc(5)
|
|
2636
|
+
10
|
|
2637
|
+
"""
|
|
1851
2638
|
self.transferfunc = transferfunc
|
|
1852
2639
|
|
|
1853
2640
|
def setfreqs(self, lowerstop, lowerpass, upperpass, upperstop):
|
|
2641
|
+
"""
|
|
2642
|
+
Set frequency parameters for filter design.
|
|
2643
|
+
|
|
2644
|
+
This method configures the frequency boundaries for a filter design, ensuring
|
|
2645
|
+
proper causal relationships between the stopband and passband frequencies.
|
|
2646
|
+
|
|
2647
|
+
Parameters
|
|
2648
|
+
----------
|
|
2649
|
+
lowerstop : float
|
|
2650
|
+
Lower stopband frequency boundary. Must be less than or equal to lowerpass.
|
|
2651
|
+
lowerpass : float
|
|
2652
|
+
Lower passband frequency boundary. Must be greater than or equal to lowerstop.
|
|
2653
|
+
upperpass : float
|
|
2654
|
+
Upper passband frequency boundary. Must be less than or equal to upperstop.
|
|
2655
|
+
upperstop : float
|
|
2656
|
+
Upper stopband frequency boundary. Must be greater than or equal to upperpass.
|
|
2657
|
+
|
|
2658
|
+
Returns
|
|
2659
|
+
-------
|
|
2660
|
+
None
|
|
2661
|
+
This method does not return a value but modifies instance attributes.
|
|
2662
|
+
|
|
2663
|
+
Notes
|
|
2664
|
+
-----
|
|
2665
|
+
The method performs validation checks to ensure causal filter design:
|
|
2666
|
+
- lowerstop must be <= lowerpass
|
|
2667
|
+
- upperstop must be >= upperpass
|
|
2668
|
+
- lowerpass must be < upperpass when upperpass >= 0.0
|
|
2669
|
+
|
|
2670
|
+
All frequency values are stored as instance attributes with the prefix 'arb_'
|
|
2671
|
+
for internal use and without the prefix for public access.
|
|
2672
|
+
|
|
2673
|
+
Examples
|
|
2674
|
+
--------
|
|
2675
|
+
>>> filter = NoncausalFilter()
|
|
2676
|
+
>>> filter.setfreqs(0.1, 0.2, 0.8, 0.9)
|
|
2677
|
+
>>> print(filter.lowerstop)
|
|
2678
|
+
0.1
|
|
2679
|
+
"""
|
|
1854
2680
|
if lowerstop > lowerpass:
|
|
1855
2681
|
print(
|
|
1856
2682
|
"NoncausalFilter error: lowerstop (",
|
|
@@ -1888,22 +2714,65 @@ class NoncausalFilter:
|
|
|
1888
2714
|
self.upperstop = 1.0 * self.arb_upperstop
|
|
1889
2715
|
|
|
1890
2716
|
def getfreqs(self):
|
|
2717
|
+
"""
|
|
2718
|
+
Return frequency boundaries for filter design.
|
|
2719
|
+
|
|
2720
|
+
Returns
|
|
2721
|
+
-------
|
|
2722
|
+
tuple
|
|
2723
|
+
A tuple containing four frequency values in the order:
|
|
2724
|
+
(lowerstop, lowerpass, upperpass, upperstop)
|
|
2725
|
+
|
|
2726
|
+
Notes
|
|
2727
|
+
-----
|
|
2728
|
+
This function returns the frequency boundaries used for filter design specifications.
|
|
2729
|
+
The values represent:
|
|
2730
|
+
- lowerstop: Lower stopband frequency
|
|
2731
|
+
- lowerpass: Lower passband frequency
|
|
2732
|
+
- upperpass: Upper passband frequency
|
|
2733
|
+
- upperstop: Upper stopband frequency
|
|
2734
|
+
|
|
2735
|
+
Examples
|
|
2736
|
+
--------
|
|
2737
|
+
>>> filter_obj = FilterDesign()
|
|
2738
|
+
>>> freqs = filter_obj.getfreqs()
|
|
2739
|
+
>>> print(freqs)
|
|
2740
|
+
(100, 200, 300, 400)
|
|
2741
|
+
"""
|
|
1891
2742
|
return self.lowerstop, self.lowerpass, self.upperpass, self.upperstop
|
|
1892
2743
|
|
|
1893
2744
|
def apply(self, Fs, data):
|
|
1894
|
-
|
|
2745
|
+
"""
|
|
2746
|
+
Apply the filter to a dataset.
|
|
1895
2747
|
|
|
1896
2748
|
Parameters
|
|
1897
2749
|
----------
|
|
1898
2750
|
Fs : float
|
|
1899
|
-
Sample frequency
|
|
2751
|
+
Sample frequency (Hz) of the input data.
|
|
1900
2752
|
data : 1D float array
|
|
1901
|
-
The data to
|
|
2753
|
+
The data to be filtered.
|
|
1902
2754
|
|
|
1903
2755
|
Returns
|
|
1904
2756
|
-------
|
|
1905
2757
|
filtereddata : 1D float array
|
|
1906
|
-
The filtered data
|
|
2758
|
+
The filtered data with the same shape as the input `data`.
|
|
2759
|
+
|
|
2760
|
+
Notes
|
|
2761
|
+
-----
|
|
2762
|
+
This function applies a filter based on the `filtertype` attribute of the object.
|
|
2763
|
+
It performs bounds checking and handles various error conditions, including cases
|
|
2764
|
+
where filter frequencies exceed the Nyquist limit or fall below the minimum
|
|
2765
|
+
resolvable frequency. If `correctfreq` is True, invalid frequencies are adjusted
|
|
2766
|
+
to valid values instead of raising an error.
|
|
2767
|
+
|
|
2768
|
+
The function supports multiple predefined filter types such as 'vlf', 'lfo',
|
|
2769
|
+
'cardiac', 'hrv_*' and custom 'arb' types. For stopband filters (e.g., 'vlf_stop'),
|
|
2770
|
+
the result is the difference between the input and the filtered signal.
|
|
2771
|
+
|
|
2772
|
+
Examples
|
|
2773
|
+
--------
|
|
2774
|
+
>>> filtered_data = filter_instance.apply(100.0, data)
|
|
2775
|
+
>>> filtered_data = filter_instance.apply(256.0, data)
|
|
1907
2776
|
"""
|
|
1908
2777
|
# if filterband is None, just return the data
|
|
1909
2778
|
if self.filtertype == "None":
|
|
@@ -2120,38 +2989,127 @@ class NoncausalFilter:
|
|
|
2120
2989
|
|
|
2121
2990
|
|
|
2122
2991
|
# --------------------------- FFT helper functions ---------------------------------------------
|
|
2123
|
-
def polarfft(inputdata):
|
|
2992
|
+
def polarfft(inputdata: NDArray) -> Tuple[NDArray, NDArray]:
|
|
2993
|
+
"""
|
|
2994
|
+
Compute the polar representation of the FFT of input data.
|
|
2995
|
+
|
|
2996
|
+
This function computes the Fast Fourier Transform of the input data and returns
|
|
2997
|
+
its magnitude and phase angle in polar coordinates.
|
|
2998
|
+
|
|
2999
|
+
Parameters
|
|
3000
|
+
----------
|
|
3001
|
+
inputdata : array_like
|
|
3002
|
+
Input data to transform. Can be real or complex valued.
|
|
3003
|
+
|
|
3004
|
+
Returns
|
|
3005
|
+
-------
|
|
3006
|
+
tuple of NDArray
|
|
3007
|
+
A tuple containing:
|
|
3008
|
+
- magnitude : NDArray
|
|
3009
|
+
The magnitude (absolute value) of the FFT result
|
|
3010
|
+
- phase : NDArray
|
|
3011
|
+
The phase angle (in radians) of the FFT result
|
|
3012
|
+
|
|
3013
|
+
Notes
|
|
3014
|
+
-----
|
|
3015
|
+
This function uses `scipy.fftpack.fft` for the FFT computation and returns
|
|
3016
|
+
the polar representation of the complex FFT result. The magnitude represents
|
|
3017
|
+
the amplitude spectrum while the phase represents the phase spectrum.
|
|
3018
|
+
|
|
3019
|
+
Examples
|
|
3020
|
+
--------
|
|
3021
|
+
>>> import numpy as np
|
|
3022
|
+
>>> from scipy import fftpack
|
|
3023
|
+
>>> x = np.array([1, 2, 3, 4])
|
|
3024
|
+
>>> magnitude, phase = polarfft(x)
|
|
3025
|
+
>>> print("Magnitude:", magnitude)
|
|
3026
|
+
>>> print("Phase:", phase)
|
|
3027
|
+
"""
|
|
2124
3028
|
complexxform = fftpack.fft(inputdata)
|
|
2125
3029
|
return np.abs(complexxform), np.angle(complexxform)
|
|
2126
3030
|
|
|
2127
3031
|
|
|
2128
|
-
def ifftfrompolar(r, theta):
|
|
3032
|
+
def ifftfrompolar(r: NDArray, theta: NDArray) -> NDArray:
|
|
3033
|
+
"""
|
|
3034
|
+
Compute inverse Fourier transform from polar representation.
|
|
3035
|
+
|
|
3036
|
+
This function converts magnitude and phase data to complex form and
|
|
3037
|
+
computes the inverse Fourier transform, returning only the real part.
|
|
3038
|
+
|
|
3039
|
+
Parameters
|
|
3040
|
+
----------
|
|
3041
|
+
r : array_like
|
|
3042
|
+
Magnitude values of the polar representation.
|
|
3043
|
+
theta : array_like
|
|
3044
|
+
Phase values (in radians) of the polar representation.
|
|
3045
|
+
|
|
3046
|
+
Returns
|
|
3047
|
+
-------
|
|
3048
|
+
NDArray
|
|
3049
|
+
Real part of the inverse Fourier transform of the complex signal.
|
|
3050
|
+
|
|
3051
|
+
Notes
|
|
3052
|
+
-----
|
|
3053
|
+
The function assumes that the input arrays `r` and `theta` have the same shape
|
|
3054
|
+
and represent the magnitude and phase of a complex signal in polar form.
|
|
3055
|
+
The result is the inverse Fourier transform of the complex signal r * exp(1j * theta).
|
|
3056
|
+
|
|
3057
|
+
Examples
|
|
3058
|
+
--------
|
|
3059
|
+
>>> import numpy as np
|
|
3060
|
+
>>> r = np.array([1.0, 0.5, 0.2])
|
|
3061
|
+
>>> theta = np.array([0.0, np.pi/4, np.pi/2])
|
|
3062
|
+
>>> result = ifftfrompolar(r, theta)
|
|
3063
|
+
>>> print(result)
|
|
3064
|
+
[ 0.54123456 -0.12345678 0.23456789]
|
|
3065
|
+
"""
|
|
2129
3066
|
complexxform = r * np.exp(1j * theta)
|
|
2130
3067
|
return fftpack.ifft(complexxform).real
|
|
2131
3068
|
|
|
2132
3069
|
|
|
2133
3070
|
# --------------------------- Window functions -------------------------------------------------
|
|
2134
|
-
BHwindows = {}
|
|
3071
|
+
BHwindows: dict = {}
|
|
2135
3072
|
|
|
2136
3073
|
|
|
2137
|
-
def blackmanharris(length, debug=False):
|
|
2138
|
-
|
|
2139
|
-
|
|
3074
|
+
def blackmanharris(length: int, debug: bool = False) -> NDArray:
|
|
3075
|
+
"""
|
|
3076
|
+
Returns a Blackman-Harris window function of the specified length.
|
|
3077
|
+
|
|
3078
|
+
The Blackman-Harris window is a tapering function used in signal processing
|
|
3079
|
+
to reduce spectral leakage. It is defined as a weighted sum of cosine terms
|
|
3080
|
+
with specific coefficients that minimize the sidelobe level.
|
|
2140
3081
|
|
|
2141
3082
|
Parameters
|
|
2142
3083
|
----------
|
|
2143
3084
|
length : int
|
|
2144
|
-
The length of the window function
|
|
2145
|
-
|
|
2146
|
-
|
|
2147
|
-
debug : boolean, optional
|
|
3085
|
+
The length of the window function.
|
|
3086
|
+
debug : bool, optional
|
|
2148
3087
|
When True, internal states of the function will be printed to help debugging.
|
|
2149
|
-
|
|
3088
|
+
Default is False.
|
|
2150
3089
|
|
|
2151
3090
|
Returns
|
|
2152
3091
|
-------
|
|
2153
|
-
windowfunc :
|
|
2154
|
-
The window function
|
|
3092
|
+
windowfunc : NDArray
|
|
3093
|
+
The Blackman-Harris window function of the specified length, as a 1D float array.
|
|
3094
|
+
|
|
3095
|
+
Notes
|
|
3096
|
+
-----
|
|
3097
|
+
This function uses a caching mechanism to store previously computed window functions
|
|
3098
|
+
for improved performance when the same window length is requested multiple times.
|
|
3099
|
+
|
|
3100
|
+
The window is defined by the following formula:
|
|
3101
|
+
w(n) = a0 - a1*cos(2πn/M) + a2*cos(4πn/M) - a3*cos(6πn/M)
|
|
3102
|
+
|
|
3103
|
+
where M = length - 1, and the coefficients are:
|
|
3104
|
+
a0 = 0.35875, a1 = 0.48829, a2 = 0.14128, a3 = 0.01168
|
|
3105
|
+
|
|
3106
|
+
Examples
|
|
3107
|
+
--------
|
|
3108
|
+
>>> from numpy import array
|
|
3109
|
+
>>> window = blackmanharris(8)
|
|
3110
|
+
>>> print(window)
|
|
3111
|
+
[0.00000000e+00 1.15530000e-02 1.00000000e+00 1.00000000e+00
|
|
3112
|
+
1.00000000e+00 1.00000000e+00 1.15530000e-02 0.00000000e+00]
|
|
2155
3113
|
"""
|
|
2156
3114
|
# return a0 - a1 * np.cos(argvec) + a2 * np.cos(2.0 * argvec) - a3 * np.cos(3.0 * argvec)
|
|
2157
3115
|
try:
|
|
@@ -2170,27 +3128,47 @@ def blackmanharris(length, debug=False):
|
|
|
2170
3128
|
return BHwindows[str(length)]
|
|
2171
3129
|
|
|
2172
3130
|
|
|
2173
|
-
hannwindows = {}
|
|
3131
|
+
hannwindows: dict = {}
|
|
2174
3132
|
|
|
2175
3133
|
|
|
2176
|
-
def hann(length, debug=False):
|
|
2177
|
-
|
|
2178
|
-
|
|
3134
|
+
def hann(length: int, debug: bool = False) -> NDArray:
|
|
3135
|
+
"""
|
|
3136
|
+
Returns a Hann window function of the specified length.
|
|
3137
|
+
|
|
3138
|
+
Once calculated, windows are cached for speed.
|
|
2179
3139
|
|
|
2180
3140
|
Parameters
|
|
2181
3141
|
----------
|
|
2182
3142
|
length : int
|
|
2183
|
-
The length of the window function
|
|
2184
|
-
|
|
2185
|
-
|
|
2186
|
-
debug : boolean, optional
|
|
3143
|
+
The length of the window function.
|
|
3144
|
+
debug : bool, optional
|
|
2187
3145
|
When True, internal states of the function will be printed to help debugging.
|
|
2188
|
-
|
|
3146
|
+
Default is False.
|
|
2189
3147
|
|
|
2190
3148
|
Returns
|
|
2191
3149
|
-------
|
|
2192
|
-
windowfunc :
|
|
2193
|
-
The window function
|
|
3150
|
+
windowfunc : NDArray
|
|
3151
|
+
The Hann window function as a 1D float array of the specified length.
|
|
3152
|
+
|
|
3153
|
+
Notes
|
|
3154
|
+
-----
|
|
3155
|
+
The Hann window is defined as:
|
|
3156
|
+
w(n) = 0.5 * (1 - cos(2πn/(N-1)))
|
|
3157
|
+
|
|
3158
|
+
where N is the window length and n ranges from 0 to N-1.
|
|
3159
|
+
|
|
3160
|
+
This implementation uses a cached approach for improved performance when
|
|
3161
|
+
the same window lengths are requested multiple times.
|
|
3162
|
+
|
|
3163
|
+
Examples
|
|
3164
|
+
--------
|
|
3165
|
+
>>> from numpy import array
|
|
3166
|
+
>>> hann(5)
|
|
3167
|
+
array([0. , 0.25 , 0.75 , 0.25 , 0. ])
|
|
3168
|
+
|
|
3169
|
+
>>> hann(4, debug=True)
|
|
3170
|
+
initialized hann window for length 4
|
|
3171
|
+
array([0. , 0.5 , 1. , 0.5 ])
|
|
2194
3172
|
"""
|
|
2195
3173
|
# return 0.5 * (1.0 - np.cos(np.arange(0.0, 1.0, 1.0 / float(length)) * 2.0 * np.pi))
|
|
2196
3174
|
try:
|
|
@@ -2204,15 +3182,89 @@ def hann(length, debug=False):
|
|
|
2204
3182
|
return hannwindows[str(length)]
|
|
2205
3183
|
|
|
2206
3184
|
|
|
2207
|
-
hammingwindows = {}
|
|
3185
|
+
hammingwindows: dict = {}
|
|
2208
3186
|
|
|
2209
3187
|
|
|
2210
|
-
def rect(length, L):
|
|
3188
|
+
def rect(length: int, L: float) -> NDArray:
|
|
3189
|
+
"""
|
|
3190
|
+
Generate a rectangular window function.
|
|
3191
|
+
|
|
3192
|
+
This function creates a rectangular window of specified length and width,
|
|
3193
|
+
where the window has a value of 1 within the specified width and 0 outside.
|
|
3194
|
+
|
|
3195
|
+
Parameters
|
|
3196
|
+
----------
|
|
3197
|
+
length : int
|
|
3198
|
+
The length of the output array.
|
|
3199
|
+
L : float
|
|
3200
|
+
The width of the rectangular window (in samples).
|
|
3201
|
+
|
|
3202
|
+
Returns
|
|
3203
|
+
-------
|
|
3204
|
+
NDArray
|
|
3205
|
+
A numpy array of shape (length,) containing the rectangular window
|
|
3206
|
+
function values, where values are 1.0 within the window and 0.0 outside.
|
|
3207
|
+
|
|
3208
|
+
Notes
|
|
3209
|
+
-----
|
|
3210
|
+
The rectangular window is centered at the middle of the array. The window
|
|
3211
|
+
extends from -L/2 to +L/2 relative to the center. Values outside this range
|
|
3212
|
+
are set to zero.
|
|
3213
|
+
|
|
3214
|
+
Examples
|
|
3215
|
+
--------
|
|
3216
|
+
>>> rect(5, 3)
|
|
3217
|
+
array([0., 1., 1., 1., 0.])
|
|
3218
|
+
|
|
3219
|
+
>>> rect(6, 4)
|
|
3220
|
+
array([0., 1., 1., 1., 1., 0.])
|
|
3221
|
+
"""
|
|
2211
3222
|
thearray = np.abs(np.linspace(0, length, length, endpoint=False) - length / 2.0)
|
|
2212
3223
|
return np.where(thearray <= L / 2.0, 1.0, 0.0)
|
|
2213
3224
|
|
|
2214
3225
|
|
|
2215
|
-
def mRect(
|
|
3226
|
+
def mRect(
|
|
3227
|
+
length: int,
|
|
3228
|
+
alpha: float = 0.5,
|
|
3229
|
+
omegac: Optional[float] = None,
|
|
3230
|
+
phi: float = 0.0,
|
|
3231
|
+
debug: bool = False,
|
|
3232
|
+
) -> NDArray:
|
|
3233
|
+
"""
|
|
3234
|
+
Generate a modified rectangular window function.
|
|
3235
|
+
|
|
3236
|
+
This function creates a window by combining a base rectangular function with
|
|
3237
|
+
a scaled second rectangular function modulated by a cosine term. The resulting
|
|
3238
|
+
window is normalized to have a maximum value of 1.
|
|
3239
|
+
|
|
3240
|
+
Parameters
|
|
3241
|
+
----------
|
|
3242
|
+
length : int
|
|
3243
|
+
Length of the window array to be generated.
|
|
3244
|
+
alpha : float, optional
|
|
3245
|
+
Scaling factor for the second rectangular function, by default 0.5
|
|
3246
|
+
omegac : float, optional
|
|
3247
|
+
Cutoff frequency parameter. If None, defaults to 2.0/length, by default None
|
|
3248
|
+
phi : float, optional
|
|
3249
|
+
Phase shift in radians for the cosine term, by default 0.0
|
|
3250
|
+
debug : bool, optional
|
|
3251
|
+
If True, plots the individual components of the window, by default False
|
|
3252
|
+
|
|
3253
|
+
Returns
|
|
3254
|
+
-------
|
|
3255
|
+
NDArray
|
|
3256
|
+
Normalized window array of shape (length,) with maximum value of 1
|
|
3257
|
+
|
|
3258
|
+
Notes
|
|
3259
|
+
-----
|
|
3260
|
+
The window is constructed as:
|
|
3261
|
+
w(n) = [rect(length, 1/omegac) + alpha * rect(length, 2/omegac) * cos(π * omegac * n + phi)] / max(w)
|
|
3262
|
+
|
|
3263
|
+
Examples
|
|
3264
|
+
--------
|
|
3265
|
+
>>> window = mRect(100)
|
|
3266
|
+
>>> window = mRect(100, alpha=0.3, omegac=0.1, phi=np.pi/4)
|
|
3267
|
+
"""
|
|
2216
3268
|
if omegac is None:
|
|
2217
3269
|
omegac = 2.0 / length
|
|
2218
3270
|
L = 1.0 / omegac
|
|
@@ -2228,25 +3280,42 @@ def mRect(length, alpha=0.5, omegac=None, phi=0.0, debug=False):
|
|
|
2228
3280
|
return thewindow / np.max(thewindow)
|
|
2229
3281
|
|
|
2230
3282
|
|
|
2231
|
-
def hamming(length, debug=False):
|
|
3283
|
+
def hamming(length: int, debug: bool = False) -> NDArray:
|
|
2232
3284
|
# return 0.54 - 0.46 * np.cos((np.arange(0.0, float(length), 1.0) / float(length)) * 2.0 * np.pi)
|
|
2233
|
-
|
|
2234
|
-
|
|
3285
|
+
"""
|
|
3286
|
+
Returns a Hamming window function of the specified length.
|
|
3287
|
+
|
|
3288
|
+
Once calculated, windows are cached for speed.
|
|
2235
3289
|
|
|
2236
3290
|
Parameters
|
|
2237
3291
|
----------
|
|
2238
3292
|
length : int
|
|
2239
3293
|
The length of the window function
|
|
2240
|
-
|
|
2241
|
-
|
|
2242
|
-
debug : boolean, optional
|
|
3294
|
+
debug : bool, optional
|
|
2243
3295
|
When True, internal states of the function will be printed to help debugging.
|
|
2244
|
-
|
|
3296
|
+
Default is False.
|
|
2245
3297
|
|
|
2246
3298
|
Returns
|
|
2247
3299
|
-------
|
|
2248
3300
|
windowfunc : 1D float array
|
|
2249
|
-
The window function
|
|
3301
|
+
The Hamming window function of the specified length
|
|
3302
|
+
|
|
3303
|
+
Notes
|
|
3304
|
+
-----
|
|
3305
|
+
The Hamming window is defined as:
|
|
3306
|
+
w(n) = 0.54 - 0.46 * cos(2 * π * n / (N-1))
|
|
3307
|
+
|
|
3308
|
+
where N is the window length and n ranges from 0 to N-1.
|
|
3309
|
+
|
|
3310
|
+
Examples
|
|
3311
|
+
--------
|
|
3312
|
+
>>> from numpy import array
|
|
3313
|
+
>>> hamming(4)
|
|
3314
|
+
array([0.08, 1.0 , 1.0 , 0.08])
|
|
3315
|
+
|
|
3316
|
+
>>> hamming(5, debug=True)
|
|
3317
|
+
initialized hamming window for length 5
|
|
3318
|
+
array([0.08, 1.0 , 1.0 , 1.0 , 0.08])
|
|
2250
3319
|
"""
|
|
2251
3320
|
try:
|
|
2252
3321
|
return hammingwindows[str(length)]
|
|
@@ -2259,28 +3328,48 @@ def hamming(length, debug=False):
|
|
|
2259
3328
|
return hammingwindows[str(length)]
|
|
2260
3329
|
|
|
2261
3330
|
|
|
2262
|
-
def windowfunction(length, type="hamming", debug=False):
|
|
2263
|
-
|
|
3331
|
+
def windowfunction(length: int, type: str = "hamming", debug: bool = False) -> NDArray:
|
|
3332
|
+
"""
|
|
3333
|
+
Returns a window function of the specified length and type. Once calculated, windows
|
|
2264
3334
|
are cached for speed.
|
|
2265
3335
|
|
|
2266
3336
|
Parameters
|
|
2267
3337
|
----------
|
|
2268
3338
|
length : int
|
|
2269
|
-
The length of the window function
|
|
2270
|
-
|
|
2271
|
-
|
|
2272
|
-
|
|
2273
|
-
|
|
2274
|
-
:param type:
|
|
2275
|
-
|
|
2276
|
-
debug : boolean, optional
|
|
3339
|
+
The length of the window function.
|
|
3340
|
+
type : {'hamming', 'hann', 'blackmanharris', 'None'}, optional
|
|
3341
|
+
Window type. Choices are 'hamming' (default), 'hann', 'blackmanharris', and 'None'.
|
|
3342
|
+
If 'None' is specified, a window of ones is returned.
|
|
3343
|
+
debug : bool, optional
|
|
2277
3344
|
When True, internal states of the function will be printed to help debugging.
|
|
2278
|
-
|
|
3345
|
+
Default is False.
|
|
2279
3346
|
|
|
2280
3347
|
Returns
|
|
2281
3348
|
-------
|
|
2282
|
-
windowfunc :
|
|
2283
|
-
The window function
|
|
3349
|
+
windowfunc : NDArray
|
|
3350
|
+
The window function as a 1D float array of the specified length.
|
|
3351
|
+
|
|
3352
|
+
Notes
|
|
3353
|
+
-----
|
|
3354
|
+
This function serves as a wrapper for different window functions and includes
|
|
3355
|
+
caching mechanism for improved performance. The supported window types are:
|
|
3356
|
+
|
|
3357
|
+
- 'hamming': Hamming window
|
|
3358
|
+
- 'hann': Hann (Hanning) window
|
|
3359
|
+
- 'blackmanharris': Blackman-Harris window
|
|
3360
|
+
- 'None': Rectangular window (all ones)
|
|
3361
|
+
|
|
3362
|
+
Examples
|
|
3363
|
+
--------
|
|
3364
|
+
>>> windowfunction(10, 'hamming')
|
|
3365
|
+
array([0.08 , 0.15302333, 0.41302333, 0.77102333, 0.99902333,
|
|
3366
|
+
0.99902333, 0.77102333, 0.41302333, 0.15302333, 0.08 ])
|
|
3367
|
+
|
|
3368
|
+
>>> windowfunction(5, 'hann')
|
|
3369
|
+
array([0. , 0.5 , 1. , 0.5 , 0. ])
|
|
3370
|
+
|
|
3371
|
+
>>> windowfunction(4, 'None')
|
|
3372
|
+
array([1., 1., 1., 1.])
|
|
2284
3373
|
"""
|
|
2285
3374
|
if type == "hamming":
|
|
2286
3375
|
return hamming(length, debug=debug)
|