py-neuromodulation 0.0.5__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 (57) hide show
  1. py_neuromodulation/__init__.py +16 -10
  2. py_neuromodulation/{nm_RMAP.py → analysis/RMAP.py} +2 -2
  3. py_neuromodulation/analysis/__init__.py +4 -0
  4. py_neuromodulation/{nm_decode.py → analysis/decode.py} +4 -4
  5. py_neuromodulation/{nm_analysis.py → analysis/feature_reader.py} +21 -20
  6. py_neuromodulation/{nm_plots.py → analysis/plots.py} +54 -12
  7. py_neuromodulation/{nm_stats.py → analysis/stats.py} +2 -8
  8. py_neuromodulation/{nm_settings.yaml → default_settings.yaml} +6 -9
  9. py_neuromodulation/features/__init__.py +31 -0
  10. py_neuromodulation/features/bandpower.py +165 -0
  11. py_neuromodulation/{nm_bispectra.py → features/bispectra.py} +8 -5
  12. py_neuromodulation/{nm_bursts.py → features/bursts.py} +14 -9
  13. py_neuromodulation/{nm_coherence.py → features/coherence.py} +17 -13
  14. py_neuromodulation/{nm_features.py → features/feature_processor.py} +30 -53
  15. py_neuromodulation/{nm_fooof.py → features/fooof.py} +11 -8
  16. py_neuromodulation/{nm_hjorth_raw.py → features/hjorth_raw.py} +10 -5
  17. py_neuromodulation/{nm_linelength.py → features/linelength.py} +1 -1
  18. py_neuromodulation/{nm_mne_connectivity.py → features/mne_connectivity.py} +5 -6
  19. py_neuromodulation/{nm_nolds.py → features/nolds.py} +5 -7
  20. py_neuromodulation/{nm_oscillatory.py → features/oscillatory.py} +7 -181
  21. py_neuromodulation/{nm_sharpwaves.py → features/sharpwaves.py} +13 -4
  22. py_neuromodulation/filter/__init__.py +3 -0
  23. py_neuromodulation/{nm_kalmanfilter.py → filter/kalman_filter.py} +67 -71
  24. py_neuromodulation/filter/kalman_filter_external.py +1890 -0
  25. py_neuromodulation/{nm_filter.py → filter/mne_filter.py} +128 -219
  26. py_neuromodulation/filter/notch_filter.py +93 -0
  27. py_neuromodulation/processing/__init__.py +10 -0
  28. py_neuromodulation/{nm_artifacts.py → processing/artifacts.py} +2 -3
  29. py_neuromodulation/{nm_preprocessing.py → processing/data_preprocessor.py} +19 -25
  30. py_neuromodulation/{nm_filter_preprocessing.py → processing/filter_preprocessing.py} +3 -4
  31. py_neuromodulation/{nm_normalization.py → processing/normalization.py} +9 -7
  32. py_neuromodulation/{nm_projection.py → processing/projection.py} +14 -14
  33. py_neuromodulation/{nm_rereference.py → processing/rereference.py} +13 -13
  34. py_neuromodulation/{nm_resample.py → processing/resample.py} +1 -4
  35. py_neuromodulation/stream/__init__.py +3 -0
  36. py_neuromodulation/{nm_run_analysis.py → stream/data_processor.py} +42 -42
  37. py_neuromodulation/stream/generator.py +53 -0
  38. py_neuromodulation/{nm_mnelsl_generator.py → stream/mnelsl_player.py} +10 -6
  39. py_neuromodulation/{nm_mnelsl_stream.py → stream/mnelsl_stream.py} +13 -9
  40. py_neuromodulation/{nm_settings.py → stream/settings.py} +27 -24
  41. py_neuromodulation/{nm_stream.py → stream/stream.py} +217 -188
  42. py_neuromodulation/utils/__init__.py +2 -0
  43. py_neuromodulation/{nm_define_nmchannels.py → utils/channels.py} +14 -9
  44. py_neuromodulation/{nm_database.py → utils/database.py} +2 -2
  45. py_neuromodulation/{nm_IO.py → utils/io.py} +42 -77
  46. py_neuromodulation/utils/keyboard.py +52 -0
  47. py_neuromodulation/{nm_logger.py → utils/logging.py} +3 -3
  48. py_neuromodulation/{nm_types.py → utils/types.py} +72 -14
  49. {py_neuromodulation-0.0.5.dist-info → py_neuromodulation-0.0.6.dist-info}/METADATA +3 -11
  50. py_neuromodulation-0.0.6.dist-info/RECORD +89 -0
  51. py_neuromodulation/FieldTrip.py +0 -589
  52. py_neuromodulation/_write_example_dataset_helper.py +0 -83
  53. py_neuromodulation/nm_generator.py +0 -45
  54. py_neuromodulation/nm_stream_abc.py +0 -166
  55. py_neuromodulation-0.0.5.dist-info/RECORD +0 -83
  56. {py_neuromodulation-0.0.5.dist-info → py_neuromodulation-0.0.6.dist-info}/WHEEL +0 -0
  57. {py_neuromodulation-0.0.5.dist-info → py_neuromodulation-0.0.6.dist-info}/licenses/LICENSE +0 -0
@@ -1,219 +1,128 @@
1
- """Module for filter functionality."""
2
-
3
- import numpy as np
4
- from typing import cast
5
- from collections.abc import Sequence
6
-
7
- from py_neuromodulation.nm_preprocessing import NMPreprocessor
8
- from py_neuromodulation import logger
9
-
10
- from mne.filter import create_filter
11
-
12
-
13
- class MNEFilter:
14
- """mne.filter wrapper
15
-
16
- This class stores for given frequency band ranges the filter
17
- coefficients with length "filter_len".
18
- The filters can then be used sequentially for band power estimation with
19
- apply_filter().
20
- Note that this filter can be a bandpass, bandstop, lowpass, or highpass filter
21
- depending on the frequency ranges given (see further details in mne.filter.create_filter).
22
-
23
- Parameters
24
- ----------
25
- f_ranges : list[tuple[float | None, float | None]]
26
- sfreq : float
27
- Sampling frequency.
28
- filter_length : str, optional
29
- Filter length. Human readable (e.g. "1000ms", "1s"), by default "999ms"
30
- l_trans_bandwidth : float | str, optional
31
- Length of the lower transition band or "auto", by default 4
32
- h_trans_bandwidth : float | str, optional
33
- Length of the higher transition band or "auto", by default 4
34
- verbose : bool | None, optional
35
- Verbosity level, by default None
36
-
37
- Attributes
38
- ----------
39
- filter_bank: np.ndarray shape (n,)
40
- Factor to upsample by.
41
- """
42
-
43
- def __init__(
44
- self,
45
- f_ranges: Sequence[tuple[float | None, float | None]],
46
- sfreq: float,
47
- filter_length: str | float = "999ms",
48
- l_trans_bandwidth: float | str = 4,
49
- h_trans_bandwidth: float | str = 4,
50
- verbose: bool | int | str | None = None,
51
- ) -> None:
52
- filter_bank = []
53
- # mne create_filter function only accepts str and int for filter_length
54
- if isinstance(filter_length, float):
55
- filter_length = int(filter_length)
56
-
57
- for f_range in f_ranges:
58
- try:
59
- filt = create_filter(
60
- None,
61
- sfreq,
62
- l_freq=f_range[0],
63
- h_freq=f_range[1],
64
- fir_design="firwin",
65
- l_trans_bandwidth=l_trans_bandwidth, # type: ignore
66
- h_trans_bandwidth=h_trans_bandwidth, # type: ignore
67
- filter_length=filter_length, # type: ignore
68
- verbose=verbose,
69
- )
70
- except ValueError:
71
- filt = create_filter(
72
- None,
73
- sfreq,
74
- l_freq=f_range[0],
75
- h_freq=f_range[1],
76
- fir_design="firwin",
77
- verbose=verbose,
78
- # filter_length=filter_length,
79
- )
80
- filter_bank.append(filt)
81
-
82
- self.num_filters = len(filter_bank)
83
- self.filter_bank = np.vstack(filter_bank)
84
-
85
- self.filters: np.ndarray
86
- self.num_channels = -1
87
-
88
-
89
- def filter_data(self, data: np.ndarray) -> np.ndarray:
90
- """Apply previously calculated (bandpass) filters to data.
91
-
92
- Parameters
93
- ----------
94
- data : np.ndarray (n_samples, ) or (n_channels, n_samples)
95
- Data to be filtered
96
- filter_bank : np.ndarray, shape (n_fbands, filter_len)
97
- Output of calc_bandpass_filters.
98
-
99
- Returns
100
- -------
101
- np.ndarray, shape (n_channels, n_fbands, n_samples)
102
- Filtered data.
103
-
104
- """
105
- from scipy.signal import fftconvolve
106
-
107
- if data.ndim > 2:
108
- raise ValueError(
109
- f"Data must have one or two dimensions. Got:"
110
- f" {data.ndim} dimensions."
111
- )
112
- if data.ndim == 1:
113
- data = np.expand_dims(data, axis=0)
114
-
115
- if self.num_channels == -1:
116
- self.num_channels = data.shape[0]
117
- self.filters = np.tile(self.filter_bank[None, :, :], (self.num_channels, 1, 1))
118
-
119
- data_tiled = np.tile(data[:, None, :], (1, self.num_filters, 1))
120
-
121
- filtered = fftconvolve(data_tiled, self.filters, axes=2, mode="same")
122
-
123
- # ensure here that the output dimension matches the input dimension
124
- if data.shape[1] != filtered.shape[-1]:
125
- # select the middle part of the filtered data
126
- middle_index = filtered.shape[-1] // 2
127
- filtered = filtered[
128
- :,
129
- :,
130
- middle_index - data.shape[1] // 2 : middle_index + data.shape[1] // 2,
131
- ]
132
-
133
- return filtered
134
-
135
-
136
- class NotchFilter(NMPreprocessor):
137
- def __init__(
138
- self,
139
- sfreq: float,
140
- line_noise: float | None = None,
141
- freqs: np.ndarray | None = None,
142
- notch_widths: int | np.ndarray | None = 3,
143
- trans_bandwidth: float = 6.8,
144
- ) -> None:
145
- if line_noise is None and freqs is None:
146
- raise ValueError(
147
- "Either line_noise or freqs must be defined if notch_filter is"
148
- "activated."
149
- )
150
-
151
- if freqs is None:
152
- freqs = np.arange(line_noise, sfreq / 2, line_noise, dtype=int)
153
-
154
- if freqs.size > 0 and freqs[-1] >= sfreq / 2:
155
- freqs = freqs[:-1]
156
-
157
- # Code is copied from filter.py notch_filter
158
- if freqs.size == 0:
159
- self.filter_bank = None
160
- logger.warning(
161
- "WARNING: notch_filter is activated but data is not being"
162
- " filtered. This may be due to a low sampling frequency or"
163
- " incorrect specifications. Make sure your settings are"
164
- f" correct. Got: {sfreq = }, {line_noise = }, {freqs = }."
165
- )
166
- return
167
-
168
- filter_length = int(sfreq - 1)
169
- if notch_widths is None:
170
- notch_widths = freqs / 200.0
171
- elif np.any(notch_widths < 0):
172
- raise ValueError("notch_widths must be >= 0")
173
- else:
174
- notch_widths = np.atleast_1d(notch_widths)
175
- if len(notch_widths) == 1:
176
- notch_widths = notch_widths[0] * np.ones_like(freqs)
177
- elif len(notch_widths) != len(freqs):
178
- raise ValueError(
179
- "notch_widths must be None, scalar, or the " "same length as freqs"
180
- )
181
- notch_widths = cast(np.ndarray, notch_widths) # For MyPy only, no runtime cost
182
-
183
- # Speed this up by computing the fourier coefficients once
184
- tb_half = trans_bandwidth / 2.0
185
- lows = [freq - nw / 2.0 - tb_half for freq, nw in zip(freqs, notch_widths)]
186
- highs = [freq + nw / 2.0 + tb_half for freq, nw in zip(freqs, notch_widths)]
187
-
188
- self.filter_bank = create_filter(
189
- data=None,
190
- sfreq=sfreq,
191
- l_freq=highs,
192
- h_freq=lows,
193
- filter_length=filter_length, # type: ignore
194
- l_trans_bandwidth=tb_half, # type: ignore
195
- h_trans_bandwidth=tb_half, # type: ignore
196
- method="fir",
197
- iir_params=None,
198
- phase="zero",
199
- fir_window="hamming",
200
- fir_design="firwin",
201
- verbose=False,
202
- )
203
-
204
- def process(self, data: np.ndarray) -> np.ndarray:
205
- if self.filter_bank is None:
206
- return data
207
-
208
- from mne.filter import _overlap_add_filter
209
-
210
- return _overlap_add_filter(
211
- x=data,
212
- h=self.filter_bank,
213
- n_fft=None,
214
- phase="zero",
215
- picks=None,
216
- n_jobs=1,
217
- copy=True,
218
- pad="reflect_limited",
219
- )
1
+ import numpy as np
2
+ from collections.abc import Sequence
3
+
4
+
5
+ class MNEFilter:
6
+ """mne.filter wrapper
7
+
8
+ This class stores for given frequency band ranges the filter
9
+ coefficients with length "filter_len".
10
+ The filters can then be used sequentially for band power estimation with
11
+ apply_filter().
12
+ Note that this filter can be a bandpass, bandstop, lowpass, or highpass filter
13
+ depending on the frequency ranges given (see further details in mne.filter.create_filter).
14
+
15
+ Parameters
16
+ ----------
17
+ f_ranges : list[tuple[float | None, float | None]]
18
+ sfreq : float
19
+ Sampling frequency.
20
+ filter_length : str, optional
21
+ Filter length. Human readable (e.g. "1000ms", "1s"), by default "999ms"
22
+ l_trans_bandwidth : float | str, optional
23
+ Length of the lower transition band or "auto", by default 4
24
+ h_trans_bandwidth : float | str, optional
25
+ Length of the higher transition band or "auto", by default 4
26
+ verbose : bool | None, optional
27
+ Verbosity level, by default None
28
+
29
+ Attributes
30
+ ----------
31
+ filter_bank: np.ndarray shape (n,)
32
+ Factor to upsample by.
33
+ """
34
+
35
+ def __init__(
36
+ self,
37
+ f_ranges: Sequence[tuple[float | None, float | None]],
38
+ sfreq: float,
39
+ filter_length: str | float = "999ms",
40
+ l_trans_bandwidth: float | str = 4,
41
+ h_trans_bandwidth: float | str = 4,
42
+ verbose: bool | int | str | None = None,
43
+ ) -> None:
44
+ from mne.filter import create_filter
45
+
46
+ filter_bank = []
47
+ # mne create_filter function only accepts str and int for filter_length
48
+ if isinstance(filter_length, float):
49
+ filter_length = int(filter_length)
50
+
51
+ for f_range in f_ranges:
52
+ try:
53
+ filt = create_filter(
54
+ None,
55
+ sfreq,
56
+ l_freq=f_range[0],
57
+ h_freq=f_range[1],
58
+ fir_design="firwin",
59
+ l_trans_bandwidth=l_trans_bandwidth, # type: ignore
60
+ h_trans_bandwidth=h_trans_bandwidth, # type: ignore
61
+ filter_length=filter_length, # type: ignore
62
+ verbose=verbose,
63
+ )
64
+ except ValueError:
65
+ filt = create_filter(
66
+ None,
67
+ sfreq,
68
+ l_freq=f_range[0],
69
+ h_freq=f_range[1],
70
+ fir_design="firwin",
71
+ verbose=verbose,
72
+ # filter_length=filter_length,
73
+ )
74
+ filter_bank.append(filt)
75
+
76
+ self.num_filters = len(filter_bank)
77
+ self.filter_bank = np.vstack(filter_bank)
78
+
79
+ self.filters: np.ndarray
80
+ self.num_channels = -1
81
+
82
+ def filter_data(self, data: np.ndarray) -> np.ndarray:
83
+ """Apply previously calculated (bandpass) filters to data.
84
+
85
+ Parameters
86
+ ----------
87
+ data : np.ndarray (n_samples, ) or (n_channels, n_samples)
88
+ Data to be filtered
89
+ filter_bank : np.ndarray, shape (n_fbands, filter_len)
90
+ Output of calc_bandpass_filters.
91
+
92
+ Returns
93
+ -------
94
+ np.ndarray, shape (n_channels, n_fbands, n_samples)
95
+ Filtered data.
96
+
97
+ """
98
+ from scipy.signal import fftconvolve
99
+
100
+ if data.ndim > 2:
101
+ raise ValueError(
102
+ f"Data must have one or two dimensions. Got:"
103
+ f" {data.ndim} dimensions."
104
+ )
105
+ if data.ndim == 1:
106
+ data = np.expand_dims(data, axis=0)
107
+
108
+ if self.num_channels == -1:
109
+ self.num_channels = data.shape[0]
110
+ self.filters = np.tile(
111
+ self.filter_bank[None, :, :], (self.num_channels, 1, 1)
112
+ )
113
+
114
+ data_tiled = np.tile(data[:, None, :], (1, self.num_filters, 1))
115
+
116
+ filtered = fftconvolve(data_tiled, self.filters, axes=2, mode="same")
117
+
118
+ # ensure here that the output dimension matches the input dimension
119
+ if data.shape[1] != filtered.shape[-1]:
120
+ # select the middle part of the filtered data
121
+ middle_index = filtered.shape[-1] // 2
122
+ filtered = filtered[
123
+ :,
124
+ :,
125
+ middle_index - data.shape[1] // 2 : middle_index + data.shape[1] // 2,
126
+ ]
127
+
128
+ return filtered
@@ -0,0 +1,93 @@
1
+ import numpy as np
2
+ from typing import cast
3
+
4
+ from py_neuromodulation.utils.types import NMPreprocessor
5
+ from py_neuromodulation import logger
6
+
7
+
8
+ class NotchFilter(NMPreprocessor):
9
+ def __init__(
10
+ self,
11
+ sfreq: float,
12
+ line_noise: float | None = None,
13
+ freqs: np.ndarray | None = None,
14
+ notch_widths: int | np.ndarray | None = 3,
15
+ trans_bandwidth: float = 6.8,
16
+ ) -> None:
17
+ from mne.filter import create_filter
18
+
19
+ if line_noise is None and freqs is None:
20
+ raise ValueError(
21
+ "Either line_noise or freqs must be defined if notch_filter is"
22
+ "activated."
23
+ )
24
+
25
+ if freqs is None:
26
+ freqs = np.arange(line_noise, sfreq / 2, line_noise, dtype=int)
27
+
28
+ if freqs.size > 0 and freqs[-1] >= sfreq / 2:
29
+ freqs = freqs[:-1]
30
+
31
+ # Code is copied from filter.py notch_filter
32
+ if freqs.size == 0:
33
+ self.filter_bank = None
34
+ logger.warning(
35
+ "WARNING: notch_filter is activated but data is not being"
36
+ " filtered. This may be due to a low sampling frequency or"
37
+ " incorrect specifications. Make sure your settings are"
38
+ f" correct. Got: {sfreq = }, {line_noise = }, {freqs = }."
39
+ )
40
+ return
41
+
42
+ filter_length = int(sfreq - 1)
43
+ if notch_widths is None:
44
+ notch_widths = freqs / 200.0
45
+ elif np.any(notch_widths < 0):
46
+ raise ValueError("notch_widths must be >= 0")
47
+ else:
48
+ notch_widths = np.atleast_1d(notch_widths)
49
+ if len(notch_widths) == 1:
50
+ notch_widths = notch_widths[0] * np.ones_like(freqs)
51
+ elif len(notch_widths) != len(freqs):
52
+ raise ValueError(
53
+ "notch_widths must be None, scalar, or the " "same length as freqs"
54
+ )
55
+ notch_widths = cast(np.ndarray, notch_widths) # For MyPy only, no runtime cost
56
+
57
+ # Speed this up by computing the fourier coefficients once
58
+ tb_half = trans_bandwidth / 2.0
59
+ lows = [freq - nw / 2.0 - tb_half for freq, nw in zip(freqs, notch_widths)]
60
+ highs = [freq + nw / 2.0 + tb_half for freq, nw in zip(freqs, notch_widths)]
61
+
62
+ self.filter_bank = create_filter(
63
+ data=None,
64
+ sfreq=sfreq,
65
+ l_freq=highs,
66
+ h_freq=lows,
67
+ filter_length=filter_length, # type: ignore
68
+ l_trans_bandwidth=tb_half, # type: ignore
69
+ h_trans_bandwidth=tb_half, # type: ignore
70
+ method="fir",
71
+ iir_params=None,
72
+ phase="zero",
73
+ fir_window="hamming",
74
+ fir_design="firwin",
75
+ verbose=False,
76
+ )
77
+
78
+ def process(self, data: np.ndarray) -> np.ndarray:
79
+ if self.filter_bank is None:
80
+ return data
81
+
82
+ from mne.filter import _overlap_add_filter
83
+
84
+ return _overlap_add_filter(
85
+ x=data,
86
+ h=self.filter_bank,
87
+ n_fft=None,
88
+ phase="zero",
89
+ picks=None,
90
+ n_jobs=1,
91
+ copy=True,
92
+ pad="reflect_limited",
93
+ )
@@ -0,0 +1,10 @@
1
+ from .artifacts import PARRMArtifactRejection
2
+ from .data_preprocessor import DataPreprocessor
3
+ from .projection import Projection, ProjectionSettings
4
+ from .normalization import FeatureNormalizer, RawNormalizer, NormalizationSettings
5
+ from .resample import Resampler, ResamplerSettings
6
+ from .rereference import ReReferencer
7
+ from .filter_preprocessing import PreprocessingFilter, FilterSettings
8
+
9
+ # Expose Notch filter also in the processing module, as it is used as a data preprocessing step
10
+ from py_neuromodulation.filter import NotchFilter
@@ -1,6 +1,3 @@
1
- from pyparrm import PARRM
2
-
3
-
4
1
  class PARRMArtifactRejection:
5
2
  """
6
3
  This module enables training of a PARRM filter before computation,
@@ -8,6 +5,8 @@ class PARRMArtifactRejection:
8
5
  https://pyparrm.readthedocs.io/en/stable/
9
6
  """
10
7
  def __init__(self, data, sampling_freq, artefact_freq, verbose=False):
8
+ from pyparrm import PARRM
9
+
11
10
  self.data = data
12
11
  self.sampling_freq = sampling_freq
13
12
  self.artefact_freq = artefact_freq
@@ -1,45 +1,37 @@
1
- from typing import Protocol, TYPE_CHECKING
2
- from inspect import getfullargspec
3
- from typing import Type
4
- from py_neuromodulation.nm_types import ImportDetails, get_class, PreprocessorName
1
+ from typing import TYPE_CHECKING, Type
2
+ from py_neuromodulation.utils.types import PreprocessorName, NMPreprocessor
5
3
 
6
4
  if TYPE_CHECKING:
7
5
  import numpy as np
8
6
  import pandas as pd
9
- from py_neuromodulation.nm_settings import NMSettings
7
+ from py_neuromodulation.stream.settings import NMSettings
10
8
 
11
-
12
- class NMPreprocessor(Protocol):
13
- def __init__(self, sfreq: float, settings: "NMSettings") -> None: ...
14
-
15
- def process(self, data: "np.ndarray") -> "np.ndarray": ...
16
-
17
-
18
- PREPROCESSOR_DICT: dict[PreprocessorName, ImportDetails] = {
19
- "preprocessing_filter": ImportDetails(
20
- "nm_filter_preprocessing", "PreprocessingFilter"
21
- ),
22
- "notch_filter": ImportDetails("nm_filter", "NotchFilter"),
23
- "raw_resampling": ImportDetails("nm_resample", "Resampler"),
24
- "re_referencing": ImportDetails("nm_rereference", "ReReferencer"),
25
- "raw_normalization": ImportDetails("nm_normalization", "RawNormalizer"),
9
+ PREPROCESSOR_DICT: dict[PreprocessorName, str] = {
10
+ "preprocessing_filter": "PreprocessingFilter",
11
+ "notch_filter": "NotchFilter",
12
+ "raw_resampling": "Resampler",
13
+ "re_referencing": "ReReferencer",
14
+ "raw_normalization": "RawNormalizer",
26
15
  }
27
16
 
28
17
 
29
- class NMPreprocessors:
18
+ class DataPreprocessor:
30
19
  "Class for initializing and holding data preprocessing classes"
31
20
 
32
21
  def __init__(
33
22
  self,
34
23
  settings: "NMSettings",
35
- nm_channels: "pd.DataFrame",
24
+ channels: "pd.DataFrame",
36
25
  sfreq: float,
37
26
  line_noise: float | None = None,
38
27
  ) -> None:
28
+ from importlib import import_module
29
+ from inspect import getfullargspec
30
+
39
31
  possible_arguments = {
40
32
  "sfreq": sfreq,
41
33
  "settings": settings,
42
- "nm_channels": nm_channels,
34
+ "channels": channels,
43
35
  "line_noise": line_noise,
44
36
  }
45
37
 
@@ -51,8 +43,10 @@ class NMPreprocessors:
51
43
 
52
44
  # Get needed preprocessor classes from settings
53
45
  preprocessor_classes: dict[str, Type[NMPreprocessor]] = {
54
- preprocessor_name: get_class(import_details)
55
- for preprocessor_name, import_details in PREPROCESSOR_DICT.items()
46
+ preprocessor_name: getattr(
47
+ import_module("py_neuromodulation.processing"), class_name
48
+ )
49
+ for preprocessor_name, class_name in PREPROCESSOR_DICT.items()
56
50
  if preprocessor_name in settings.preprocessing
57
51
  }
58
52
 
@@ -3,11 +3,10 @@ import numpy as np
3
3
  from pydantic import Field
4
4
  from typing import TYPE_CHECKING
5
5
 
6
- from py_neuromodulation.nm_types import BoolSelector, FrequencyRange
7
- from py_neuromodulation.nm_preprocessing import NMPreprocessor
6
+ from py_neuromodulation.utils.types import BoolSelector, FrequencyRange, NMPreprocessor
8
7
 
9
8
  if TYPE_CHECKING:
10
- from py_neuromodulation.nm_settings import NMSettings
9
+ from py_neuromodulation import NMSettings
11
10
 
12
11
 
13
12
  FILTER_SETTINGS_MAP = {
@@ -50,7 +49,7 @@ class FilterSettings(BoolSelector):
50
49
 
51
50
  class PreprocessingFilter(NMPreprocessor):
52
51
  def __init__(self, settings: "NMSettings", sfreq: float) -> None:
53
- from py_neuromodulation.nm_filter import MNEFilter
52
+ from py_neuromodulation.filter import MNEFilter
54
53
 
55
54
  self.filters: list[MNEFilter] = [
56
55
  MNEFilter(
@@ -3,11 +3,15 @@
3
3
  import numpy as np
4
4
  from typing import TYPE_CHECKING, Callable, Literal, get_args
5
5
 
6
- from py_neuromodulation.nm_types import NMBaseModel, Field, NormMethod
7
- from py_neuromodulation.nm_preprocessing import NMPreprocessor
6
+ from py_neuromodulation.utils.types import (
7
+ NMBaseModel,
8
+ Field,
9
+ NormMethod,
10
+ NMPreprocessor,
11
+ )
8
12
 
9
13
  if TYPE_CHECKING:
10
- from py_neuromodulation.nm_settings import NMSettings
14
+ from py_neuromodulation import NMSettings
11
15
 
12
16
  NormalizerType = Literal["raw", "feature"]
13
17
 
@@ -29,7 +33,6 @@ class Normalizer(NMPreprocessor):
29
33
  settings: "NMSettings",
30
34
  type: NormalizerType,
31
35
  ) -> None:
32
-
33
36
  self.type = type
34
37
  self.settings: NormalizationSettings
35
38
 
@@ -86,7 +89,6 @@ class Normalizer(NMPreprocessor):
86
89
  if self.settings.clip:
87
90
  data = data.clip(min=-self.settings.clip, max=self.settings.clip)
88
91
 
89
-
90
92
  self.previous = self.previous[-self.num_samples_normalize + 1 :]
91
93
 
92
94
  data = np.nan_to_num(data)
@@ -143,13 +145,13 @@ def norm_median(current, previous):
143
145
 
144
146
  def norm_zscore(current, previous):
145
147
  std = nan_std(previous, axis=0)
146
- std[std == 0] = 1 # same behavior as sklearn
148
+ std[std == 0] = 1 # same behavior as sklearn
147
149
  return (current - nan_mean(previous, axis=0)) / std
148
150
 
149
151
 
150
152
  def norm_zscore_median(current, previous):
151
153
  std = nan_std(previous, axis=0)
152
- std[std == 0] = 1 # same behavior as sklearn
154
+ std[std == 0] = 1 # same behavior as sklearn
153
155
  return (current - nan_median(previous, axis=0)) / std
154
156
 
155
157