py-neuromodulation 0.0.4__py3-none-any.whl → 0.0.6__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.
Files changed (109) hide show
  1. py_neuromodulation/ConnectivityDecoding/_get_grid_hull.m +34 -34
  2. py_neuromodulation/ConnectivityDecoding/_get_grid_whole_brain.py +95 -106
  3. py_neuromodulation/ConnectivityDecoding/_helper_write_connectome.py +107 -119
  4. py_neuromodulation/__init__.py +80 -13
  5. py_neuromodulation/{nm_RMAP.py → analysis/RMAP.py} +496 -531
  6. py_neuromodulation/analysis/__init__.py +4 -0
  7. py_neuromodulation/{nm_decode.py → analysis/decode.py} +918 -992
  8. py_neuromodulation/{nm_analysis.py → analysis/feature_reader.py} +994 -1074
  9. py_neuromodulation/{nm_plots.py → analysis/plots.py} +627 -612
  10. py_neuromodulation/{nm_stats.py → analysis/stats.py} +458 -480
  11. py_neuromodulation/data/README +6 -6
  12. py_neuromodulation/data/dataset_description.json +8 -8
  13. py_neuromodulation/data/participants.json +32 -32
  14. py_neuromodulation/data/participants.tsv +2 -2
  15. py_neuromodulation/data/sub-testsub/ses-EphysMedOff/ieeg/sub-testsub_ses-EphysMedOff_space-mni_coordsystem.json +5 -5
  16. py_neuromodulation/data/sub-testsub/ses-EphysMedOff/ieeg/sub-testsub_ses-EphysMedOff_space-mni_electrodes.tsv +11 -11
  17. py_neuromodulation/data/sub-testsub/ses-EphysMedOff/ieeg/sub-testsub_ses-EphysMedOff_task-gripforce_run-0_channels.tsv +11 -11
  18. py_neuromodulation/data/sub-testsub/ses-EphysMedOff/ieeg/sub-testsub_ses-EphysMedOff_task-gripforce_run-0_ieeg.json +18 -18
  19. py_neuromodulation/data/sub-testsub/ses-EphysMedOff/ieeg/sub-testsub_ses-EphysMedOff_task-gripforce_run-0_ieeg.vhdr +35 -35
  20. py_neuromodulation/data/sub-testsub/ses-EphysMedOff/ieeg/sub-testsub_ses-EphysMedOff_task-gripforce_run-0_ieeg.vmrk +13 -13
  21. py_neuromodulation/data/sub-testsub/ses-EphysMedOff/sub-testsub_ses-EphysMedOff_scans.tsv +2 -2
  22. py_neuromodulation/default_settings.yaml +241 -0
  23. py_neuromodulation/features/__init__.py +31 -0
  24. py_neuromodulation/features/bandpower.py +165 -0
  25. py_neuromodulation/features/bispectra.py +157 -0
  26. py_neuromodulation/features/bursts.py +297 -0
  27. py_neuromodulation/features/coherence.py +255 -0
  28. py_neuromodulation/features/feature_processor.py +121 -0
  29. py_neuromodulation/features/fooof.py +142 -0
  30. py_neuromodulation/features/hjorth_raw.py +57 -0
  31. py_neuromodulation/features/linelength.py +21 -0
  32. py_neuromodulation/features/mne_connectivity.py +148 -0
  33. py_neuromodulation/features/nolds.py +94 -0
  34. py_neuromodulation/features/oscillatory.py +249 -0
  35. py_neuromodulation/features/sharpwaves.py +432 -0
  36. py_neuromodulation/filter/__init__.py +3 -0
  37. py_neuromodulation/filter/kalman_filter.py +67 -0
  38. py_neuromodulation/filter/kalman_filter_external.py +1890 -0
  39. py_neuromodulation/filter/mne_filter.py +128 -0
  40. py_neuromodulation/filter/notch_filter.py +93 -0
  41. py_neuromodulation/grid_cortex.tsv +40 -40
  42. py_neuromodulation/liblsl/libpugixml.so.1.12 +0 -0
  43. py_neuromodulation/liblsl/linux/bionic_amd64/liblsl.1.16.2.so +0 -0
  44. py_neuromodulation/liblsl/linux/bookworm_amd64/liblsl.1.16.2.so +0 -0
  45. py_neuromodulation/liblsl/linux/focal_amd46/liblsl.1.16.2.so +0 -0
  46. py_neuromodulation/liblsl/linux/jammy_amd64/liblsl.1.16.2.so +0 -0
  47. py_neuromodulation/liblsl/linux/jammy_x86/liblsl.1.16.2.so +0 -0
  48. py_neuromodulation/liblsl/linux/noble_amd64/liblsl.1.16.2.so +0 -0
  49. py_neuromodulation/liblsl/macos/amd64/liblsl.1.16.2.dylib +0 -0
  50. py_neuromodulation/liblsl/macos/arm64/liblsl.1.16.0.dylib +0 -0
  51. py_neuromodulation/liblsl/windows/amd64/liblsl.1.16.2.dll +0 -0
  52. py_neuromodulation/liblsl/windows/x86/liblsl.1.16.2.dll +0 -0
  53. py_neuromodulation/processing/__init__.py +10 -0
  54. py_neuromodulation/{nm_artifacts.py → processing/artifacts.py} +29 -25
  55. py_neuromodulation/processing/data_preprocessor.py +77 -0
  56. py_neuromodulation/processing/filter_preprocessing.py +78 -0
  57. py_neuromodulation/processing/normalization.py +175 -0
  58. py_neuromodulation/{nm_projection.py → processing/projection.py} +370 -394
  59. py_neuromodulation/{nm_rereference.py → processing/rereference.py} +97 -95
  60. py_neuromodulation/{nm_resample.py → processing/resample.py} +56 -50
  61. py_neuromodulation/stream/__init__.py +3 -0
  62. py_neuromodulation/stream/data_processor.py +325 -0
  63. py_neuromodulation/stream/generator.py +53 -0
  64. py_neuromodulation/stream/mnelsl_player.py +94 -0
  65. py_neuromodulation/stream/mnelsl_stream.py +120 -0
  66. py_neuromodulation/stream/settings.py +292 -0
  67. py_neuromodulation/stream/stream.py +427 -0
  68. py_neuromodulation/utils/__init__.py +2 -0
  69. py_neuromodulation/{nm_define_nmchannels.py → utils/channels.py} +305 -302
  70. py_neuromodulation/utils/database.py +149 -0
  71. py_neuromodulation/utils/io.py +378 -0
  72. py_neuromodulation/utils/keyboard.py +52 -0
  73. py_neuromodulation/utils/logging.py +66 -0
  74. py_neuromodulation/utils/types.py +251 -0
  75. {py_neuromodulation-0.0.4.dist-info → py_neuromodulation-0.0.6.dist-info}/METADATA +28 -33
  76. py_neuromodulation-0.0.6.dist-info/RECORD +89 -0
  77. {py_neuromodulation-0.0.4.dist-info → py_neuromodulation-0.0.6.dist-info}/WHEEL +1 -1
  78. {py_neuromodulation-0.0.4.dist-info → py_neuromodulation-0.0.6.dist-info}/licenses/LICENSE +21 -21
  79. py_neuromodulation/FieldTrip.py +0 -589
  80. py_neuromodulation/_write_example_dataset_helper.py +0 -65
  81. py_neuromodulation/nm_EpochStream.py +0 -92
  82. py_neuromodulation/nm_IO.py +0 -417
  83. py_neuromodulation/nm_across_patient_decoding.py +0 -927
  84. py_neuromodulation/nm_bispectra.py +0 -168
  85. py_neuromodulation/nm_bursts.py +0 -198
  86. py_neuromodulation/nm_coherence.py +0 -205
  87. py_neuromodulation/nm_cohortwrapper.py +0 -435
  88. py_neuromodulation/nm_eval_timing.py +0 -239
  89. py_neuromodulation/nm_features.py +0 -116
  90. py_neuromodulation/nm_features_abc.py +0 -39
  91. py_neuromodulation/nm_filter.py +0 -219
  92. py_neuromodulation/nm_filter_preprocessing.py +0 -91
  93. py_neuromodulation/nm_fooof.py +0 -159
  94. py_neuromodulation/nm_generator.py +0 -37
  95. py_neuromodulation/nm_hjorth_raw.py +0 -73
  96. py_neuromodulation/nm_kalmanfilter.py +0 -58
  97. py_neuromodulation/nm_linelength.py +0 -33
  98. py_neuromodulation/nm_mne_connectivity.py +0 -112
  99. py_neuromodulation/nm_nolds.py +0 -93
  100. py_neuromodulation/nm_normalization.py +0 -214
  101. py_neuromodulation/nm_oscillatory.py +0 -448
  102. py_neuromodulation/nm_run_analysis.py +0 -435
  103. py_neuromodulation/nm_settings.json +0 -338
  104. py_neuromodulation/nm_settings.py +0 -68
  105. py_neuromodulation/nm_sharpwaves.py +0 -401
  106. py_neuromodulation/nm_stream_abc.py +0 -218
  107. py_neuromodulation/nm_stream_offline.py +0 -359
  108. py_neuromodulation/utils/_logging.py +0 -24
  109. py_neuromodulation-0.0.4.dist-info/RECORD +0 -72
@@ -1,448 +0,0 @@
1
- from typing import Iterable
2
-
3
- import numpy as np
4
- from scipy import fft, signal
5
-
6
- from py_neuromodulation import nm_filter, nm_features_abc, nm_kalmanfilter
7
-
8
-
9
- class OscillatoryFeature(nm_features_abc.Feature):
10
- def __init__(
11
- self, settings: dict, ch_names: Iterable[str], sfreq: float
12
- ) -> None:
13
- self.s = settings
14
- self.sfreq = sfreq
15
- self.ch_names = ch_names
16
- self.KF_dict = {}
17
-
18
- self.f_ranges_dict = settings["frequency_ranges_hz"]
19
- self.fband_names = list(settings["frequency_ranges_hz"].keys())
20
- self.f_ranges = list(settings["frequency_ranges_hz"].values())
21
-
22
- @staticmethod
23
- def test_settings_osc(
24
- s: dict,
25
- ch_names: Iterable[str],
26
- sfreq: int | float,
27
- osc_feature_name: str,
28
- ):
29
- assert (
30
- fb[0] < sfreq / 2 and fb[1] < sfreq / 2
31
- for fb in s["frequency_ranges_hz"].values()
32
- ), (
33
- "the frequency band ranges need to be smaller than the nyquist frequency"
34
- f"got sfreq = {sfreq} and fband ranges {s['frequency_ranges_hz']}"
35
- )
36
-
37
- if osc_feature_name != "bandpass_filter_settings":
38
- assert isinstance(
39
- s[osc_feature_name]["windowlength_ms"], int
40
- ), f"windowlength_ms needs to be type int, got {s[osc_feature_name]['windowlength_ms']}"
41
-
42
- assert (
43
- s[osc_feature_name]["windowlength_ms"]
44
- <= s["segment_length_features_ms"]
45
- ), (
46
- f"oscillatory feature windowlength_ms = ({s[osc_feature_name]['windowlength_ms']})"
47
- f"needs to be smaller than"
48
- f"s['segment_length_features_ms'] = {s['segment_length_features_ms']}",
49
- )
50
- else:
51
- for seg_length in s[osc_feature_name][
52
- "segment_lengths_ms"
53
- ].values():
54
- assert isinstance(
55
- seg_length, int
56
- ), f"segment length has to be type int, got {seg_length}"
57
- assert isinstance(
58
- s[osc_feature_name]["log_transform"], bool
59
- ), f"log_transform needs to be type bool, got {s[osc_feature_name]['log_transform']}"
60
-
61
- assert isinstance(s["frequency_ranges_hz"], dict)
62
-
63
- assert (
64
- isinstance(value, list)
65
- for value in s["frequency_ranges_hz"].values()
66
- )
67
- assert (len(value) == 2 for value in s["frequency_ranges_hz"].values())
68
-
69
- assert (
70
- isinstance(value[0], list)
71
- for value in s["frequency_ranges_hz"].values()
72
- )
73
-
74
- assert (
75
- len(value[0]) == 2 for value in s["frequency_ranges_hz"].values()
76
- )
77
-
78
- assert (
79
- isinstance(value[1], (float, int))
80
- for value in s["frequency_ranges_hz"].values()
81
- )
82
-
83
- def init_KF(self, feature: str) -> None:
84
- for f_band in self.s["kalman_filter_settings"]["frequency_bands"]:
85
- for channel in self.ch_names:
86
- self.KF_dict[
87
- "_".join([channel, feature, f_band])
88
- ] = nm_kalmanfilter.define_KF(
89
- self.s["kalman_filter_settings"]["Tp"],
90
- self.s["kalman_filter_settings"]["sigma_w"],
91
- self.s["kalman_filter_settings"]["sigma_v"],
92
- )
93
-
94
- def update_KF(self, feature_calc: float, KF_name: str) -> float:
95
- if KF_name in self.KF_dict:
96
- self.KF_dict[KF_name].predict()
97
- self.KF_dict[KF_name].update(feature_calc)
98
- feature_calc = self.KF_dict[KF_name].x[0]
99
- return feature_calc
100
-
101
- def estimate_osc_features(
102
- self,
103
- features_compute: dict,
104
- data: np.ndarray,
105
- feature_name: np.ndarray,
106
- est_name: str,
107
- ):
108
- for feature_est_name in list(self.s[est_name]["features"].keys()):
109
- if self.s[est_name]["features"][feature_est_name] is True:
110
- # switch case for feature_est_name
111
- match feature_est_name:
112
- case "mean":
113
- features_compute[
114
- f"{feature_name}_{feature_est_name}"
115
- ] = np.nanmean(data)
116
- case "median":
117
- features_compute[
118
- f"{feature_name}_{feature_est_name}"
119
- ] = np.nanmedian(data)
120
- case "std":
121
- features_compute[
122
- f"{feature_name}_{feature_est_name}"
123
- ] = np.nanstd(data)
124
- case "max":
125
- features_compute[
126
- f"{feature_name}_{feature_est_name}"
127
- ] = np.nanmax(data)
128
-
129
- return features_compute
130
-
131
-
132
- class FFT(OscillatoryFeature):
133
- def __init__(
134
- self,
135
- settings: dict,
136
- ch_names: Iterable[str],
137
- sfreq: float,
138
- ) -> None:
139
- super().__init__(settings, ch_names, sfreq)
140
-
141
- if self.s["fft_settings"]["log_transform"]:
142
- self.log_transform = True
143
- else:
144
- self.log_transform = False
145
-
146
- window_ms = self.s["fft_settings"]["windowlength_ms"]
147
- self.window_samples = int(-np.floor(window_ms / 1000 * sfreq))
148
- self.freqs = fft.rfftfreq(
149
- -self.window_samples, 1 / np.floor(self.sfreq)
150
- )
151
-
152
- self.feature_params = []
153
- for ch_idx, ch_name in enumerate(self.ch_names):
154
- for fband, f_range in self.f_ranges_dict.items():
155
- idx_range = np.where(
156
- (self.freqs >= f_range[0]) & (self.freqs < f_range[1])
157
- )[0]
158
- feature_name = "_".join([ch_name, "fft", fband])
159
- self.feature_params.append((ch_idx, feature_name, idx_range))
160
-
161
- @staticmethod
162
- def test_settings(s: dict, ch_names: Iterable[str], sfreq: int | float):
163
- OscillatoryFeature.test_settings_osc(s, ch_names, sfreq, "fft_settings")
164
-
165
- def calc_feature(self, data: np.ndarray, features_compute: dict) -> dict:
166
- data = data[:, self.window_samples :]
167
- Z = np.abs(fft.rfft(data))
168
-
169
- if self.log_transform:
170
- Z = np.log10(Z)
171
-
172
- for ch_idx, feature_name, idx_range in self.feature_params:
173
- Z_ch = Z[ch_idx, idx_range]
174
-
175
- features_compute = self.estimate_osc_features(
176
- features_compute, Z_ch, feature_name, "fft_settings"
177
- )
178
-
179
- for ch_idx, ch_name in enumerate(self.ch_names):
180
- if self.s["fft_settings"]["return_spectrum"]:
181
- features_compute.update(
182
- {
183
- f"{ch_name}_fft_psd_{str(f)}": Z[ch_idx][idx]
184
- for idx, f in enumerate(self.freqs.astype(int))
185
- }
186
- )
187
-
188
- return features_compute
189
-
190
-
191
- class Welch(OscillatoryFeature):
192
- def __init__(
193
- self,
194
- settings: dict,
195
- ch_names: Iterable[str],
196
- sfreq: float,
197
- ) -> None:
198
- super().__init__(settings, ch_names, sfreq)
199
-
200
- self.log_transform = self.s["welch_settings"]["log_transform"]
201
-
202
- self.feature_params = []
203
- for ch_idx, ch_name in enumerate(self.ch_names):
204
- for fband, f_range in self.f_ranges_dict.items():
205
- feature_name = "_".join([ch_name, "welch", fband])
206
- self.feature_params.append((ch_idx, feature_name, f_range))
207
-
208
- @staticmethod
209
- def test_settings(s: dict, ch_names: Iterable[str], sfreq: int | float):
210
- OscillatoryFeature.test_settings_osc(
211
- s, ch_names, sfreq, "welch_settings"
212
- )
213
-
214
- def calc_feature(self, data: np.ndarray, features_compute: dict) -> dict:
215
- freqs, Z = signal.welch(
216
- data,
217
- fs=self.sfreq,
218
- window="hann",
219
- nperseg=self.sfreq,
220
- noverlap=None,
221
- )
222
-
223
- if self.log_transform:
224
- Z = np.log10(Z)
225
-
226
- for ch_idx, feature_name, f_range in self.feature_params:
227
- Z_ch = Z[ch_idx]
228
-
229
- idx_range = np.where((freqs >= f_range[0]) & (freqs <= f_range[1]))[
230
- 0
231
- ]
232
-
233
- features_compute = self.estimate_osc_features(
234
- features_compute,
235
- Z_ch[idx_range],
236
- feature_name,
237
- "welch_settings",
238
- )
239
-
240
- for ch_idx, ch_name in enumerate(self.ch_names):
241
- if self.s["welch_settings"]["return_spectrum"]:
242
- features_compute.update(
243
- {
244
- f"{ch_name}_welch_psd_{str(f)}": Z[ch_idx][idx]
245
- for idx, f in enumerate(freqs.astype(int))
246
- }
247
- )
248
-
249
- return features_compute
250
-
251
-
252
- class STFT(OscillatoryFeature):
253
- def __init__(
254
- self,
255
- settings: dict,
256
- ch_names: Iterable[str],
257
- sfreq: float,
258
- ) -> None:
259
- super().__init__(settings, ch_names, sfreq)
260
-
261
- self.nperseg = int(self.s["stft_settings"]["windowlength_ms"])
262
- self.log_transform = self.s["stft_settings"]["log_transform"]
263
-
264
- self.feature_params = []
265
- for ch_idx, ch_name in enumerate(self.ch_names):
266
- for fband, f_range in self.f_ranges_dict.items():
267
- feature_name = "_".join([ch_name, "stft", fband])
268
- self.feature_params.append((ch_idx, feature_name, f_range))
269
-
270
- @staticmethod
271
- def test_settings(s: dict, ch_names: Iterable[str], sfreq: int | float):
272
- OscillatoryFeature.test_settings_osc(
273
- s, ch_names, sfreq, "stft_settings"
274
- )
275
-
276
- def calc_feature(self, data: np.ndarray, features_compute: dict) -> dict:
277
- freqs, _, Zxx = signal.stft(
278
- data,
279
- fs=self.sfreq,
280
- window="hamming",
281
- nperseg=self.nperseg,
282
- boundary="even",
283
- )
284
- Z = np.abs(Zxx)
285
- if self.log_transform:
286
- Z = np.log10(Z)
287
- for ch_idx, feature_name, f_range in self.feature_params:
288
- Z_ch = Z[ch_idx]
289
- idx_range = np.where((freqs >= f_range[0]) & (freqs <= f_range[1]))[
290
- 0
291
- ]
292
-
293
- features_compute = self.estimate_osc_features(
294
- features_compute,
295
- Z_ch[idx_range, :],
296
- feature_name,
297
- "stft_settings",
298
- )
299
-
300
- for ch_idx, ch_name in enumerate(self.ch_names):
301
- if self.s["stft_settings"]["return_spectrum"]:
302
- Z_ch_mean = Z[ch_idx].mean(axis=1)
303
- features_compute.update(
304
- {
305
- f"{ch_name}_stft_psd_{str(f)}": Z_ch_mean[idx]
306
- for idx, f in enumerate(freqs.astype(int))
307
- }
308
- )
309
-
310
- return features_compute
311
-
312
-
313
- class BandPower(OscillatoryFeature):
314
- def __init__(
315
- self,
316
- settings: dict,
317
- ch_names: Iterable[str],
318
- sfreq: float,
319
- use_kf: bool = None,
320
- ) -> None:
321
- super().__init__(settings, ch_names, sfreq)
322
- bp_settings = self.s["bandpass_filter_settings"]
323
-
324
- self.bandpass_filter = nm_filter.MNEFilter(
325
- f_ranges=list(self.f_ranges_dict.values()),
326
- sfreq=self.sfreq,
327
- filter_length=self.sfreq - 1,
328
- verbose=False,
329
- )
330
-
331
- self.log_transform = bp_settings["log_transform"]
332
-
333
- if use_kf is True or (
334
- use_kf is None and bp_settings["kalman_filter"] is True
335
- ):
336
- self.init_KF("bandpass_activity")
337
-
338
- bp_features = ["activity", "mobility", "complexity"]
339
- seglengths = bp_settings["segment_lengths_ms"]
340
-
341
- self.feature_params = []
342
- for ch_idx, ch_name in enumerate(self.ch_names):
343
- for f_band_idx, f_band in enumerate(self.f_ranges_dict):
344
- seglength_ms = seglengths[f_band]
345
- seglen = int(np.floor(self.sfreq / 1000 * seglength_ms))
346
- for bp_feature, v in bp_settings["bandpower_features"].items():
347
- if v is True:
348
- if bp_feature not in bp_features:
349
- raise ValueError()
350
- feature_name = "_".join(
351
- [ch_name, "bandpass", bp_feature, f_band]
352
- )
353
- self.feature_params.append(
354
- (
355
- ch_idx,
356
- ch_name,
357
- f_band,
358
- f_band_idx,
359
- seglen,
360
- bp_feature,
361
- feature_name,
362
- )
363
- )
364
-
365
- @staticmethod
366
- def test_settings(s: dict, ch_names: Iterable[str], sfreq: int | float):
367
- OscillatoryFeature.test_settings_osc(
368
- s, ch_names, sfreq, "bandpass_filter_settings"
369
- )
370
-
371
- assert (
372
- isinstance(value, bool)
373
- for value in s["bandpass_filter_settings"][
374
- "bandpower_features"
375
- ].values()
376
- )
377
-
378
- assert any(
379
- value is True
380
- for value in s["bandpass_filter_settings"][
381
- "bandpower_features"
382
- ].values()
383
- ), "Set at least one bandpower_feature to True."
384
-
385
- for fband_name, seg_length_fband in s["bandpass_filter_settings"][
386
- "segment_lengths_ms"
387
- ].items():
388
- assert isinstance(seg_length_fband, int), (
389
- f"bandpass segment_lengths_ms for {fband_name} "
390
- f"needs to be of type int, got {seg_length_fband}"
391
- )
392
-
393
- assert seg_length_fband <= s["segment_length_features_ms"], (
394
- f"segment length {seg_length_fband} needs to be smaller than "
395
- f" s['segment_length_features_ms'] = {s['segment_length_features_ms']}"
396
- )
397
-
398
- for fband_name in list(s["frequency_ranges_hz"].keys()):
399
- assert fband_name in list(
400
- s["bandpass_filter_settings"]["segment_lengths_ms"].keys()
401
- ), (
402
- f"frequency range {fband_name} "
403
- "needs to be defined in s['bandpass_filter_settings']['segment_lengths_ms']"
404
- )
405
-
406
- def calc_feature(self, data: np.ndarray, features_compute: dict) -> dict:
407
- data = self.bandpass_filter.filter_data(data)
408
-
409
- for (
410
- ch_idx,
411
- ch_name,
412
- f_band,
413
- f_band_idx,
414
- seglen,
415
- bp_feature,
416
- feature_name,
417
- ) in self.feature_params:
418
- if bp_feature == "activity":
419
- if self.log_transform:
420
- feature_calc = np.log10(
421
- np.var(data[ch_idx, f_band_idx, -seglen:])
422
- )
423
- else:
424
- feature_calc = np.var(data[ch_idx, f_band_idx, -seglen:])
425
- elif bp_feature == "mobility":
426
- deriv_variance = np.var(
427
- np.diff(data[ch_idx, f_band_idx, -seglen:])
428
- )
429
- feature_calc = np.sqrt(
430
- deriv_variance / np.var(data[ch_idx, f_band_idx, -seglen:])
431
- )
432
- elif bp_feature == "complexity":
433
- dat_deriv = np.diff(data[ch_idx, f_band_idx, -seglen:])
434
- deriv_variance = np.var(dat_deriv)
435
- mobility = np.sqrt(
436
- deriv_variance / np.var(data[ch_idx, f_band_idx, -seglen:])
437
- )
438
- dat_deriv_2 = np.diff(dat_deriv)
439
- dat_deriv_2_var = np.var(dat_deriv_2)
440
- deriv_mobility = np.sqrt(dat_deriv_2_var / deriv_variance)
441
- feature_calc = deriv_mobility / mobility
442
-
443
- if self.KF_dict and (bp_feature == "activity"):
444
- feature_calc = self.update_KF(feature_calc, feature_name)
445
-
446
- features_compute[feature_name] = np.nan_to_num(feature_calc)
447
-
448
- return features_compute