ezmsg-sigproc 2.6.0__py3-none-any.whl → 2.8.0__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.
- ezmsg/sigproc/__version__.py +2 -2
- ezmsg/sigproc/activation.py +1 -1
- ezmsg/sigproc/adaptive_lattice_notch.py +1 -2
- ezmsg/sigproc/affinetransform.py +26 -5
- ezmsg/sigproc/aggregate.py +6 -6
- ezmsg/sigproc/bandpower.py +6 -6
- ezmsg/sigproc/butterworthzerophase.py +1 -1
- ezmsg/sigproc/coordinatespaces.py +142 -0
- ezmsg/sigproc/decimate.py +1 -1
- ezmsg/sigproc/denormalize.py +3 -4
- ezmsg/sigproc/detrend.py +1 -1
- ezmsg/sigproc/diff.py +3 -4
- ezmsg/sigproc/downsample.py +5 -6
- ezmsg/sigproc/ewma.py +45 -9
- ezmsg/sigproc/extract_axis.py +1 -2
- ezmsg/sigproc/fbcca.py +4 -4
- ezmsg/sigproc/filter.py +3 -4
- ezmsg/sigproc/filterbank.py +5 -5
- ezmsg/sigproc/filterbankdesign.py +4 -4
- ezmsg/sigproc/fir_hilbert.py +1 -1
- ezmsg/sigproc/linear.py +118 -0
- ezmsg/sigproc/math/abs.py +3 -0
- ezmsg/sigproc/math/add.py +1 -1
- ezmsg/sigproc/math/clip.py +3 -0
- ezmsg/sigproc/math/difference.py +2 -0
- ezmsg/sigproc/math/invert.py +2 -0
- ezmsg/sigproc/math/log.py +3 -0
- ezmsg/sigproc/math/scale.py +2 -0
- ezmsg/sigproc/quantize.py +1 -2
- ezmsg/sigproc/resample.py +4 -4
- ezmsg/sigproc/rollingscaler.py +4 -4
- ezmsg/sigproc/sampler.py +6 -6
- ezmsg/sigproc/scaler.py +56 -8
- ezmsg/sigproc/signalinjector.py +3 -4
- ezmsg/sigproc/slicer.py +5 -6
- ezmsg/sigproc/spectrogram.py +4 -4
- ezmsg/sigproc/spectrum.py +5 -6
- ezmsg/sigproc/transpose.py +5 -6
- ezmsg/sigproc/util/axisarray_buffer.py +2 -0
- ezmsg/sigproc/util/buffer.py +4 -0
- ezmsg/sigproc/util/sparse.py +2 -0
- ezmsg/sigproc/wavelets.py +4 -4
- ezmsg/sigproc/window.py +5 -5
- ezmsg_sigproc-2.8.0.dist-info/METADATA +60 -0
- ezmsg_sigproc-2.8.0.dist-info/RECORD +65 -0
- ezmsg_sigproc-2.6.0.dist-info/METADATA +0 -73
- ezmsg_sigproc-2.6.0.dist-info/RECORD +0 -63
- {ezmsg_sigproc-2.6.0.dist-info → ezmsg_sigproc-2.8.0.dist-info}/WHEEL +0 -0
- {ezmsg_sigproc-2.6.0.dist-info → ezmsg_sigproc-2.8.0.dist-info}/licenses/LICENSE +0 -0
ezmsg/sigproc/linear.py
ADDED
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
"""Apply a linear transformation: output = scale * input + offset.
|
|
2
|
+
|
|
3
|
+
Supports per-element scale and offset along a specified axis.
|
|
4
|
+
Uses Array API for compatibility with numpy, cupy, torch, etc.
|
|
5
|
+
|
|
6
|
+
For full matrix transformations, use :obj:`AffineTransformTransformer` instead.
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
import ezmsg.core as ez
|
|
10
|
+
import numpy as np
|
|
11
|
+
import numpy.typing as npt
|
|
12
|
+
from array_api_compat import get_namespace
|
|
13
|
+
from ezmsg.util.messages.axisarray import AxisArray
|
|
14
|
+
from ezmsg.util.messages.util import replace
|
|
15
|
+
|
|
16
|
+
from .base import BaseStatefulTransformer, BaseTransformerUnit, processor_state
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
class LinearTransformSettings(ez.Settings):
|
|
20
|
+
scale: float | list[float] | npt.ArrayLike = 1.0
|
|
21
|
+
"""Scale factor(s). Can be a scalar (applied to all elements) or an array
|
|
22
|
+
matching the size of the specified axis for per-element scaling."""
|
|
23
|
+
|
|
24
|
+
offset: float | list[float] | npt.ArrayLike = 0.0
|
|
25
|
+
"""Offset value(s). Can be a scalar (applied to all elements) or an array
|
|
26
|
+
matching the size of the specified axis for per-element offset."""
|
|
27
|
+
|
|
28
|
+
axis: str | None = None
|
|
29
|
+
"""Axis along which to apply per-element scale/offset. If None, scalar
|
|
30
|
+
scale/offset are broadcast to all elements."""
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
@processor_state
|
|
34
|
+
class LinearTransformState:
|
|
35
|
+
scale: npt.NDArray = None
|
|
36
|
+
"""Prepared scale array for broadcasting."""
|
|
37
|
+
|
|
38
|
+
offset: npt.NDArray = None
|
|
39
|
+
"""Prepared offset array for broadcasting."""
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
class LinearTransformTransformer(
|
|
43
|
+
BaseStatefulTransformer[LinearTransformSettings, AxisArray, AxisArray, LinearTransformState]
|
|
44
|
+
):
|
|
45
|
+
"""Apply linear transformation: output = scale * input + offset.
|
|
46
|
+
|
|
47
|
+
This transformer is optimized for element-wise linear operations with
|
|
48
|
+
optional per-channel (or per-axis) coefficients. For full matrix
|
|
49
|
+
transformations, use :obj:`AffineTransformTransformer` instead.
|
|
50
|
+
|
|
51
|
+
Examples:
|
|
52
|
+
# Uniform scaling and offset
|
|
53
|
+
>>> transformer = LinearTransformTransformer(LinearTransformSettings(scale=2.0, offset=1.0))
|
|
54
|
+
|
|
55
|
+
# Per-channel scaling (e.g., for 3-channel data along "ch" axis)
|
|
56
|
+
>>> transformer = LinearTransformTransformer(LinearTransformSettings(
|
|
57
|
+
... scale=[0.5, 1.0, 2.0],
|
|
58
|
+
... offset=[0.0, 0.1, 0.2],
|
|
59
|
+
... axis="ch"
|
|
60
|
+
... ))
|
|
61
|
+
"""
|
|
62
|
+
|
|
63
|
+
def _hash_message(self, message: AxisArray) -> int:
|
|
64
|
+
"""Hash based on shape and axis to detect when broadcast shapes need recalculation."""
|
|
65
|
+
axis = self.settings.axis
|
|
66
|
+
if axis is not None:
|
|
67
|
+
axis_idx = message.get_axis_idx(axis)
|
|
68
|
+
return hash((message.data.ndim, axis_idx, message.data.shape[axis_idx]))
|
|
69
|
+
return hash(message.data.ndim)
|
|
70
|
+
|
|
71
|
+
def _reset_state(self, message: AxisArray) -> None:
|
|
72
|
+
"""Prepare scale/offset arrays with proper broadcast shapes."""
|
|
73
|
+
xp = get_namespace(message.data)
|
|
74
|
+
ndim = message.data.ndim
|
|
75
|
+
|
|
76
|
+
scale = self.settings.scale
|
|
77
|
+
offset = self.settings.offset
|
|
78
|
+
|
|
79
|
+
# Convert settings to arrays
|
|
80
|
+
if isinstance(scale, (list, np.ndarray)):
|
|
81
|
+
scale = xp.asarray(scale, dtype=xp.float64)
|
|
82
|
+
else:
|
|
83
|
+
# Scalar: create a 0-d array
|
|
84
|
+
scale = xp.asarray(float(scale), dtype=xp.float64)
|
|
85
|
+
|
|
86
|
+
if isinstance(offset, (list, np.ndarray)):
|
|
87
|
+
offset = xp.asarray(offset, dtype=xp.float64)
|
|
88
|
+
else:
|
|
89
|
+
# Scalar: create a 0-d array
|
|
90
|
+
offset = xp.asarray(float(offset), dtype=xp.float64)
|
|
91
|
+
|
|
92
|
+
# If axis is specified and we have 1-d arrays, reshape for proper broadcasting
|
|
93
|
+
if self.settings.axis is not None and ndim > 0:
|
|
94
|
+
axis_idx = message.get_axis_idx(self.settings.axis)
|
|
95
|
+
|
|
96
|
+
if scale.ndim == 1:
|
|
97
|
+
# Create shape for broadcasting: all 1s except at axis_idx
|
|
98
|
+
broadcast_shape = [1] * ndim
|
|
99
|
+
broadcast_shape[axis_idx] = scale.shape[0]
|
|
100
|
+
scale = xp.reshape(scale, broadcast_shape)
|
|
101
|
+
|
|
102
|
+
if offset.ndim == 1:
|
|
103
|
+
broadcast_shape = [1] * ndim
|
|
104
|
+
broadcast_shape[axis_idx] = offset.shape[0]
|
|
105
|
+
offset = xp.reshape(offset, broadcast_shape)
|
|
106
|
+
|
|
107
|
+
self._state.scale = scale
|
|
108
|
+
self._state.offset = offset
|
|
109
|
+
|
|
110
|
+
def _process(self, message: AxisArray) -> AxisArray:
|
|
111
|
+
result = message.data * self._state.scale + self._state.offset
|
|
112
|
+
return replace(message, data=result)
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
class LinearTransform(BaseTransformerUnit[LinearTransformSettings, AxisArray, AxisArray, LinearTransformTransformer]):
|
|
116
|
+
"""Unit wrapper for LinearTransformTransformer."""
|
|
117
|
+
|
|
118
|
+
SETTINGS = LinearTransformSettings
|
ezmsg/sigproc/math/abs.py
CHANGED
ezmsg/sigproc/math/add.py
CHANGED
ezmsg/sigproc/math/clip.py
CHANGED
ezmsg/sigproc/math/difference.py
CHANGED
ezmsg/sigproc/math/invert.py
CHANGED
ezmsg/sigproc/math/log.py
CHANGED
ezmsg/sigproc/math/scale.py
CHANGED
ezmsg/sigproc/quantize.py
CHANGED
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
import ezmsg.core as ez
|
|
2
2
|
import numpy as np
|
|
3
|
+
from ezmsg.baseproc import BaseTransformer, BaseTransformerUnit
|
|
3
4
|
from ezmsg.util.messages.axisarray import AxisArray, replace
|
|
4
5
|
|
|
5
|
-
from .base import BaseTransformer, BaseTransformerUnit
|
|
6
|
-
|
|
7
6
|
|
|
8
7
|
class QuantizeSettings(ez.Settings):
|
|
9
8
|
"""
|
ezmsg/sigproc/resample.py
CHANGED
|
@@ -5,14 +5,14 @@ import time
|
|
|
5
5
|
import ezmsg.core as ez
|
|
6
6
|
import numpy as np
|
|
7
7
|
import scipy.interpolate
|
|
8
|
-
from ezmsg.
|
|
9
|
-
from ezmsg.util.messages.util import replace
|
|
10
|
-
|
|
11
|
-
from .base import (
|
|
8
|
+
from ezmsg.baseproc import (
|
|
12
9
|
BaseConsumerUnit,
|
|
13
10
|
BaseStatefulProcessor,
|
|
14
11
|
processor_state,
|
|
15
12
|
)
|
|
13
|
+
from ezmsg.util.messages.axisarray import AxisArray, LinearAxis
|
|
14
|
+
from ezmsg.util.messages.util import replace
|
|
15
|
+
|
|
16
16
|
from .util.axisarray_buffer import HybridAxisArrayBuffer, HybridAxisBuffer
|
|
17
17
|
from .util.buffer import UpdateStrategy
|
|
18
18
|
|
ezmsg/sigproc/rollingscaler.py
CHANGED
|
@@ -3,14 +3,14 @@ from collections import deque
|
|
|
3
3
|
import ezmsg.core as ez
|
|
4
4
|
import numpy as np
|
|
5
5
|
import numpy.typing as npt
|
|
6
|
-
from ezmsg.
|
|
7
|
-
from ezmsg.util.messages.util import replace
|
|
8
|
-
|
|
9
|
-
from ezmsg.sigproc.base import (
|
|
6
|
+
from ezmsg.baseproc import (
|
|
10
7
|
BaseAdaptiveTransformer,
|
|
11
8
|
BaseAdaptiveTransformerUnit,
|
|
12
9
|
processor_state,
|
|
13
10
|
)
|
|
11
|
+
from ezmsg.util.messages.axisarray import AxisArray
|
|
12
|
+
from ezmsg.util.messages.util import replace
|
|
13
|
+
|
|
14
14
|
from ezmsg.sigproc.sampler import SampleMessage
|
|
15
15
|
|
|
16
16
|
|
ezmsg/sigproc/sampler.py
CHANGED
|
@@ -6,12 +6,7 @@ from collections import deque
|
|
|
6
6
|
|
|
7
7
|
import ezmsg.core as ez
|
|
8
8
|
import numpy as np
|
|
9
|
-
from ezmsg.
|
|
10
|
-
AxisArray,
|
|
11
|
-
)
|
|
12
|
-
from ezmsg.util.messages.util import replace
|
|
13
|
-
|
|
14
|
-
from .base import (
|
|
9
|
+
from ezmsg.baseproc import (
|
|
15
10
|
BaseConsumerUnit,
|
|
16
11
|
BaseProducerUnit,
|
|
17
12
|
BaseStatefulProducer,
|
|
@@ -19,6 +14,11 @@ from .base import (
|
|
|
19
14
|
BaseTransformerUnit,
|
|
20
15
|
processor_state,
|
|
21
16
|
)
|
|
17
|
+
from ezmsg.util.messages.axisarray import (
|
|
18
|
+
AxisArray,
|
|
19
|
+
)
|
|
20
|
+
from ezmsg.util.messages.util import replace
|
|
21
|
+
|
|
22
22
|
from .util.axisarray_buffer import HybridAxisArrayBuffer
|
|
23
23
|
from .util.buffer import UpdateStrategy
|
|
24
24
|
from .util.message import SampleMessage, SampleTriggerMessage
|
ezmsg/sigproc/scaler.py
CHANGED
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
import typing
|
|
2
2
|
|
|
3
|
+
import ezmsg.core as ez
|
|
3
4
|
import numpy as np
|
|
4
|
-
from ezmsg.
|
|
5
|
-
from ezmsg.util.messages.axisarray import AxisArray
|
|
6
|
-
from ezmsg.util.messages.util import replace
|
|
7
|
-
|
|
8
|
-
from .base import (
|
|
5
|
+
from ezmsg.baseproc import (
|
|
9
6
|
BaseStatefulTransformer,
|
|
10
7
|
BaseTransformerUnit,
|
|
11
8
|
processor_state,
|
|
12
9
|
)
|
|
10
|
+
from ezmsg.util.generator import consumer
|
|
11
|
+
from ezmsg.util.messages.axisarray import AxisArray
|
|
12
|
+
from ezmsg.util.messages.util import replace
|
|
13
13
|
|
|
14
14
|
# Imports for backwards compatibility with previous module location
|
|
15
15
|
from .ewma import EWMA_Deprecated as EWMA_Deprecated
|
|
@@ -83,11 +83,38 @@ class AdaptiveStandardScalerTransformer(
|
|
|
83
83
|
]
|
|
84
84
|
):
|
|
85
85
|
def _reset_state(self, message: AxisArray) -> None:
|
|
86
|
-
self._state.samps_ewma = EWMATransformer(
|
|
87
|
-
|
|
86
|
+
self._state.samps_ewma = EWMATransformer(
|
|
87
|
+
time_constant=self.settings.time_constant,
|
|
88
|
+
axis=self.settings.axis,
|
|
89
|
+
accumulate=self.settings.accumulate,
|
|
90
|
+
)
|
|
91
|
+
self._state.vars_sq_ewma = EWMATransformer(
|
|
92
|
+
time_constant=self.settings.time_constant,
|
|
93
|
+
axis=self.settings.axis,
|
|
94
|
+
accumulate=self.settings.accumulate,
|
|
95
|
+
)
|
|
96
|
+
|
|
97
|
+
@property
|
|
98
|
+
def accumulate(self) -> bool:
|
|
99
|
+
"""Whether to accumulate statistics from incoming samples."""
|
|
100
|
+
return self.settings.accumulate
|
|
101
|
+
|
|
102
|
+
@accumulate.setter
|
|
103
|
+
def accumulate(self, value: bool) -> None:
|
|
104
|
+
"""
|
|
105
|
+
Set the accumulate mode and propagate to child EWMA transformers.
|
|
106
|
+
|
|
107
|
+
Args:
|
|
108
|
+
value: If True, update statistics with each sample.
|
|
109
|
+
If False, only apply current statistics without updating.
|
|
110
|
+
"""
|
|
111
|
+
if self._state.samps_ewma is not None:
|
|
112
|
+
self._state.samps_ewma.settings = replace(self._state.samps_ewma.settings, accumulate=value)
|
|
113
|
+
if self._state.vars_sq_ewma is not None:
|
|
114
|
+
self._state.vars_sq_ewma.settings = replace(self._state.vars_sq_ewma.settings, accumulate=value)
|
|
88
115
|
|
|
89
116
|
def _process(self, message: AxisArray) -> AxisArray:
|
|
90
|
-
# Update step
|
|
117
|
+
# Update step (respects accumulate setting via child EWMAs)
|
|
91
118
|
mean_message = self._state.samps_ewma(message)
|
|
92
119
|
var_sq_message = self._state.vars_sq_ewma(replace(message, data=message.data**2))
|
|
93
120
|
|
|
@@ -109,6 +136,27 @@ class AdaptiveStandardScaler(
|
|
|
109
136
|
):
|
|
110
137
|
SETTINGS = AdaptiveStandardScalerSettings
|
|
111
138
|
|
|
139
|
+
@ez.subscriber(BaseTransformerUnit.INPUT_SETTINGS)
|
|
140
|
+
async def on_settings(self, msg: AdaptiveStandardScalerSettings) -> None:
|
|
141
|
+
"""
|
|
142
|
+
Handle settings updates with smart reset behavior.
|
|
143
|
+
|
|
144
|
+
Only resets state if `axis` changes (structural change).
|
|
145
|
+
Changes to `time_constant` or `accumulate` are applied without
|
|
146
|
+
resetting accumulated statistics.
|
|
147
|
+
"""
|
|
148
|
+
old_axis = self.SETTINGS.axis
|
|
149
|
+
self.apply_settings(msg)
|
|
150
|
+
|
|
151
|
+
if msg.axis != old_axis:
|
|
152
|
+
# Axis changed - need full reset
|
|
153
|
+
self.create_processor()
|
|
154
|
+
else:
|
|
155
|
+
# Update accumulate on processor (propagates to child EWMAs)
|
|
156
|
+
self.processor.accumulate = msg.accumulate
|
|
157
|
+
# Also update own settings reference
|
|
158
|
+
self.processor.settings = msg
|
|
159
|
+
|
|
112
160
|
|
|
113
161
|
# Backwards compatibility...
|
|
114
162
|
def scaler_np(time_constant: float = 1.0, axis: str | None = None) -> AdaptiveStandardScalerTransformer:
|
ezmsg/sigproc/signalinjector.py
CHANGED
|
@@ -1,14 +1,13 @@
|
|
|
1
1
|
import ezmsg.core as ez
|
|
2
2
|
import numpy as np
|
|
3
3
|
import numpy.typing as npt
|
|
4
|
-
from ezmsg.
|
|
5
|
-
from ezmsg.util.messages.util import replace
|
|
6
|
-
|
|
7
|
-
from .base import (
|
|
4
|
+
from ezmsg.baseproc import (
|
|
8
5
|
BaseAsyncTransformer,
|
|
9
6
|
BaseTransformerUnit,
|
|
10
7
|
processor_state,
|
|
11
8
|
)
|
|
9
|
+
from ezmsg.util.messages.axisarray import AxisArray
|
|
10
|
+
from ezmsg.util.messages.util import replace
|
|
12
11
|
|
|
13
12
|
|
|
14
13
|
class SignalInjectorSettings(ez.Settings):
|
ezmsg/sigproc/slicer.py
CHANGED
|
@@ -1,6 +1,11 @@
|
|
|
1
1
|
import ezmsg.core as ez
|
|
2
2
|
import numpy as np
|
|
3
3
|
import numpy.typing as npt
|
|
4
|
+
from ezmsg.baseproc import (
|
|
5
|
+
BaseStatefulTransformer,
|
|
6
|
+
BaseTransformerUnit,
|
|
7
|
+
processor_state,
|
|
8
|
+
)
|
|
4
9
|
from ezmsg.util.messages.axisarray import (
|
|
5
10
|
AxisArray,
|
|
6
11
|
AxisBase,
|
|
@@ -8,12 +13,6 @@ from ezmsg.util.messages.axisarray import (
|
|
|
8
13
|
slice_along_axis,
|
|
9
14
|
)
|
|
10
15
|
|
|
11
|
-
from .base import (
|
|
12
|
-
BaseStatefulTransformer,
|
|
13
|
-
BaseTransformerUnit,
|
|
14
|
-
processor_state,
|
|
15
|
-
)
|
|
16
|
-
|
|
17
16
|
"""
|
|
18
17
|
Slicer:Select a subset of data along a particular axis.
|
|
19
18
|
"""
|
ezmsg/sigproc/spectrogram.py
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
from typing import Generator
|
|
2
2
|
|
|
3
3
|
import ezmsg.core as ez
|
|
4
|
-
from ezmsg.
|
|
5
|
-
from ezmsg.util.messages.modify import modify_axis
|
|
6
|
-
|
|
7
|
-
from .base import (
|
|
4
|
+
from ezmsg.baseproc import (
|
|
8
5
|
BaseStatefulProcessor,
|
|
9
6
|
BaseTransformerUnit,
|
|
10
7
|
CompositeProcessor,
|
|
11
8
|
)
|
|
9
|
+
from ezmsg.util.messages.axisarray import AxisArray
|
|
10
|
+
from ezmsg.util.messages.modify import modify_axis
|
|
11
|
+
|
|
12
12
|
from .spectrum import (
|
|
13
13
|
SpectralOutput,
|
|
14
14
|
SpectralTransform,
|
ezmsg/sigproc/spectrum.py
CHANGED
|
@@ -5,18 +5,17 @@ from functools import partial
|
|
|
5
5
|
import ezmsg.core as ez
|
|
6
6
|
import numpy as np
|
|
7
7
|
import numpy.typing as npt
|
|
8
|
+
from ezmsg.baseproc import (
|
|
9
|
+
BaseStatefulTransformer,
|
|
10
|
+
BaseTransformerUnit,
|
|
11
|
+
processor_state,
|
|
12
|
+
)
|
|
8
13
|
from ezmsg.util.messages.axisarray import (
|
|
9
14
|
AxisArray,
|
|
10
15
|
replace,
|
|
11
16
|
slice_along_axis,
|
|
12
17
|
)
|
|
13
18
|
|
|
14
|
-
from .base import (
|
|
15
|
-
BaseStatefulTransformer,
|
|
16
|
-
BaseTransformerUnit,
|
|
17
|
-
processor_state,
|
|
18
|
-
)
|
|
19
|
-
|
|
20
19
|
|
|
21
20
|
class OptionsEnum(enum.Enum):
|
|
22
21
|
@classmethod
|
ezmsg/sigproc/transpose.py
CHANGED
|
@@ -2,16 +2,15 @@ from types import EllipsisType
|
|
|
2
2
|
|
|
3
3
|
import ezmsg.core as ez
|
|
4
4
|
import numpy as np
|
|
5
|
-
from ezmsg.
|
|
6
|
-
AxisArray,
|
|
7
|
-
replace,
|
|
8
|
-
)
|
|
9
|
-
|
|
10
|
-
from .base import (
|
|
5
|
+
from ezmsg.baseproc import (
|
|
11
6
|
BaseStatefulTransformer,
|
|
12
7
|
BaseTransformerUnit,
|
|
13
8
|
processor_state,
|
|
14
9
|
)
|
|
10
|
+
from ezmsg.util.messages.axisarray import (
|
|
11
|
+
AxisArray,
|
|
12
|
+
replace,
|
|
13
|
+
)
|
|
15
14
|
|
|
16
15
|
|
|
17
16
|
class TransposeSettings(ez.Settings):
|
ezmsg/sigproc/util/buffer.py
CHANGED
ezmsg/sigproc/util/sparse.py
CHANGED
ezmsg/sigproc/wavelets.py
CHANGED
|
@@ -4,14 +4,14 @@ import ezmsg.core as ez
|
|
|
4
4
|
import numpy as np
|
|
5
5
|
import numpy.typing as npt
|
|
6
6
|
import pywt
|
|
7
|
-
from ezmsg.
|
|
8
|
-
from ezmsg.util.messages.util import replace
|
|
9
|
-
|
|
10
|
-
from .base import (
|
|
7
|
+
from ezmsg.baseproc import (
|
|
11
8
|
BaseStatefulTransformer,
|
|
12
9
|
BaseTransformerUnit,
|
|
13
10
|
processor_state,
|
|
14
11
|
)
|
|
12
|
+
from ezmsg.util.messages.axisarray import AxisArray
|
|
13
|
+
from ezmsg.util.messages.util import replace
|
|
14
|
+
|
|
15
15
|
from .filterbank import FilterbankMode, MinPhaseMode, filterbank
|
|
16
16
|
|
|
17
17
|
|
ezmsg/sigproc/window.py
CHANGED
|
@@ -6,6 +6,11 @@ import ezmsg.core as ez
|
|
|
6
6
|
import numpy.typing as npt
|
|
7
7
|
import sparse
|
|
8
8
|
from array_api_compat import get_namespace, is_pydata_sparse_namespace
|
|
9
|
+
from ezmsg.baseproc import (
|
|
10
|
+
BaseStatefulTransformer,
|
|
11
|
+
BaseTransformerUnit,
|
|
12
|
+
processor_state,
|
|
13
|
+
)
|
|
9
14
|
from ezmsg.util.messages.axisarray import (
|
|
10
15
|
AxisArray,
|
|
11
16
|
replace,
|
|
@@ -13,11 +18,6 @@ from ezmsg.util.messages.axisarray import (
|
|
|
13
18
|
sliding_win_oneaxis,
|
|
14
19
|
)
|
|
15
20
|
|
|
16
|
-
from .base import (
|
|
17
|
-
BaseStatefulTransformer,
|
|
18
|
-
BaseTransformerUnit,
|
|
19
|
-
processor_state,
|
|
20
|
-
)
|
|
21
21
|
from .util.profile import profile_subpub
|
|
22
22
|
from .util.sparse import sliding_win_oneaxis as sparse_sliding_win_oneaxis
|
|
23
23
|
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: ezmsg-sigproc
|
|
3
|
+
Version: 2.8.0
|
|
4
|
+
Summary: Timeseries signal processing implementations in ezmsg
|
|
5
|
+
Author-email: Griffin Milsap <griffin.milsap@gmail.com>, Preston Peranich <pperanich@gmail.com>, Chadwick Boulay <chadwick.boulay@gmail.com>, Kyle McGraw <kmcgraw@blackrockneuro.com>
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
License-File: LICENSE
|
|
8
|
+
Requires-Python: >=3.10.15
|
|
9
|
+
Requires-Dist: array-api-compat>=1.11.1
|
|
10
|
+
Requires-Dist: ezmsg-baseproc>=1.1.0
|
|
11
|
+
Requires-Dist: ezmsg>=3.6.0
|
|
12
|
+
Requires-Dist: numba>=0.61.0
|
|
13
|
+
Requires-Dist: numpy>=1.26.0
|
|
14
|
+
Requires-Dist: pywavelets>=1.6.0
|
|
15
|
+
Requires-Dist: scipy>=1.13.1
|
|
16
|
+
Requires-Dist: sparse>=0.15.4
|
|
17
|
+
Description-Content-Type: text/markdown
|
|
18
|
+
|
|
19
|
+
# ezmsg-sigproc
|
|
20
|
+
|
|
21
|
+
Signal processing primitives for the [ezmsg](https://www.ezmsg.org) message-passing framework.
|
|
22
|
+
|
|
23
|
+
## Features
|
|
24
|
+
|
|
25
|
+
* **Filtering** - Chebyshev, comb filters, and more
|
|
26
|
+
* **Spectral analysis** - Spectrogram, spectrum, and wavelet transforms
|
|
27
|
+
* **Resampling** - Downsample, decimate, and resample operations
|
|
28
|
+
* **Windowing** - Sliding windows and buffering utilities
|
|
29
|
+
* **Math operations** - Arithmetic, log, abs, difference, and more
|
|
30
|
+
* **Signal generation** - Synthetic signal generators
|
|
31
|
+
|
|
32
|
+
All modules use `AxisArray` as the primary data structure for passing signals between components.
|
|
33
|
+
|
|
34
|
+
## Installation
|
|
35
|
+
|
|
36
|
+
Install from PyPI:
|
|
37
|
+
|
|
38
|
+
```bash
|
|
39
|
+
pip install ezmsg-sigproc
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
Or install from GitHub for the latest development version:
|
|
43
|
+
|
|
44
|
+
```bash
|
|
45
|
+
pip install git+https://github.com/ezmsg-org/ezmsg-sigproc.git@dev
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
## Documentation
|
|
49
|
+
|
|
50
|
+
Full documentation is available at [ezmsg.org](https://www.ezmsg.org).
|
|
51
|
+
|
|
52
|
+
## Development
|
|
53
|
+
|
|
54
|
+
We use [`uv`](https://docs.astral.sh/uv/) for development.
|
|
55
|
+
|
|
56
|
+
1. Fork and clone the repository
|
|
57
|
+
2. `uv sync` to create a virtual environment and install dependencies
|
|
58
|
+
3. `uv run pre-commit install` to set up linting and formatting hooks
|
|
59
|
+
4. `uv run pytest tests` to run the test suite
|
|
60
|
+
5. Submit a PR against the `dev` branch
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
ezmsg/sigproc/__init__.py,sha256=8K4IcOA3-pfzadoM6s2Sfg5460KlJUocGgyTJTJl96U,52
|
|
2
|
+
ezmsg/sigproc/__version__.py,sha256=9o_P9mg_lm8dZdRjWfkpikVSLuPB26JLjcQeqWLe_GI,704
|
|
3
|
+
ezmsg/sigproc/activation.py,sha256=83vnTa3ZcC4Q3VSWcGfaqhCEqYRNySUOyVpMHZXfz-c,2755
|
|
4
|
+
ezmsg/sigproc/adaptive_lattice_notch.py,sha256=ThUR48mbSHuThkimtD0j4IXNMrOVcpZgGhE7PCYfXhU,8818
|
|
5
|
+
ezmsg/sigproc/affinetransform.py,sha256=jl7DiSa5Yb0qsmFJbfSiSeGmvK1SGoBgycFC5JU5DVY,9434
|
|
6
|
+
ezmsg/sigproc/aggregate.py,sha256=yc3Hnak0yhucqlTCv9Isg6BKR24s6rMZqbZKpayyBgM,9048
|
|
7
|
+
ezmsg/sigproc/bandpower.py,sha256=dAhH56sUrXNhcRFymTTwjdM_KcU5OxFzrR_sxIPAxyw,2264
|
|
8
|
+
ezmsg/sigproc/base.py,sha256=SJvKEb8gw6mUMwlV5sH0iPG0bXrgS8tvkPwhI-j89MQ,3672
|
|
9
|
+
ezmsg/sigproc/butterworthfilter.py,sha256=NKTGkgjvlmC1Dc9gD2Z6UBzUq12KicfnczrzM5ZTosk,5255
|
|
10
|
+
ezmsg/sigproc/butterworthzerophase.py,sha256=Df3F1QBBE39FBjNi67wvTsb1bSdTRTSTZXbZiKFlxC4,4105
|
|
11
|
+
ezmsg/sigproc/cheby.py,sha256=B8pGt5_pOBpNZCmaibNl_NKkyuasd8ZEJXeTDCTaino,3711
|
|
12
|
+
ezmsg/sigproc/combfilter.py,sha256=MSxr1I-jBePW_9AuCiv3RQ1HUNxIsNhLk0q1Iu8ikAw,4766
|
|
13
|
+
ezmsg/sigproc/coordinatespaces.py,sha256=NWbQVvizmiU4F3AIwHHhiZ30Kg2IeSW0fRaa-yXkn-c,4610
|
|
14
|
+
ezmsg/sigproc/decimate.py,sha256=DCX9p4ZrcGoQ9di-jmPKqiKERTkvTAtSqLg8chQLp84,2336
|
|
15
|
+
ezmsg/sigproc/denormalize.py,sha256=OACzoINCISNUmZcR2pqWfxi3p8uuBLCz1PMw4XNwOCs,3035
|
|
16
|
+
ezmsg/sigproc/detrend.py,sha256=2C-dhVy-ty4b22aE07kIF3VjqCoFitoZqyrX6hAjXYQ,894
|
|
17
|
+
ezmsg/sigproc/diff.py,sha256=m0g1KQXEooSM3V2oLx_MyYEZqdXm04jI9B4V-HjMUa4,2777
|
|
18
|
+
ezmsg/sigproc/downsample.py,sha256=Jqxt1Va1FrQLH1wUQpP0U79iQARTTHEKklKHy7yGL2o,3679
|
|
19
|
+
ezmsg/sigproc/ewma.py,sha256=ecLq1ZlON85NWdW_5cz9chWirxjf4y9zCPMOt3IqQuk,7723
|
|
20
|
+
ezmsg/sigproc/ewmfilter.py,sha256=9AuvVn3TDdf5R4bVolYNM46AtDVHFJa8MLGltY6mYPE,4795
|
|
21
|
+
ezmsg/sigproc/extract_axis.py,sha256=T2e9zW8N0bwOj4_zlB3I0oT0iwaBijpzF6wrFsCfD24,1593
|
|
22
|
+
ezmsg/sigproc/fbcca.py,sha256=JYFWsMDRJEWwUNujr4EsFL5t1ux-cnBGamNVrCRO_RA,12043
|
|
23
|
+
ezmsg/sigproc/filter.py,sha256=IWg3J5IGVdv7kfp4zaKRzfjEuRa5xNzcq6fHtq4tPCM,11604
|
|
24
|
+
ezmsg/sigproc/filterbank.py,sha256=tD7fn4dZzEvsmp_sSn16VVJ4WcJ5sN5lsSuNTLDCQZ8,13056
|
|
25
|
+
ezmsg/sigproc/filterbankdesign.py,sha256=vLXQVJwoFEK4V6umqzcr1PJKcwv6pGO29klSWQXk7y0,4712
|
|
26
|
+
ezmsg/sigproc/fir_hilbert.py,sha256=ByZDsDFjbJx-EgLZF85vZCPQbprQaiMEuG2dyvTPiDY,10855
|
|
27
|
+
ezmsg/sigproc/fir_pmc.py,sha256=Ze2pd9K8XrdDhgJZG2E7x-5C2hfd6kIns4bYjTJsBvc,6997
|
|
28
|
+
ezmsg/sigproc/firfilter.py,sha256=7r_I476nYuixJsuwc_hQ0Fbq8WB0gnYBZUKs3zultOQ,3790
|
|
29
|
+
ezmsg/sigproc/gaussiansmoothing.py,sha256=BfXm9YQoOtieM4ABK2KRgxeQz055rd7mqtTVqmjT3Rk,2672
|
|
30
|
+
ezmsg/sigproc/kaiser.py,sha256=dIwgHbLXUHPtdotsGNLE9VG_clhcMgvVnSoFkMVgF9M,3483
|
|
31
|
+
ezmsg/sigproc/linear.py,sha256=o5HNEQMx2e6FrFOJskJeKCJwZmSN1uO-1LgBxERzmEE,4535
|
|
32
|
+
ezmsg/sigproc/messages.py,sha256=KQczHTeifn4BZycChN8ZcpfZoQW3lC_xuFmN72QT97s,925
|
|
33
|
+
ezmsg/sigproc/quantize.py,sha256=uSM2z2xXwL0dgSltyzLEmlKjaJZ2meA3PDWX8_bM0Hs,2195
|
|
34
|
+
ezmsg/sigproc/resample.py,sha256=3mm9pvxryNVhQuTCIMW3ToUkUfbVOCsIgvXUiurit1Y,11389
|
|
35
|
+
ezmsg/sigproc/rollingscaler.py,sha256=e-smSKDhmDD2nWIf6I77CtRxQp_7sHS268SGPi7aXp8,8499
|
|
36
|
+
ezmsg/sigproc/sampler.py,sha256=iOk2YoUX22u9iTjFKimzP5V074RDBVcmswgfyxvZRZo,10761
|
|
37
|
+
ezmsg/sigproc/scaler.py,sha256=oBZa6uzyftChvk6aqBD5clil6pedx3IF-dptrb74EA0,5888
|
|
38
|
+
ezmsg/sigproc/signalinjector.py,sha256=mB62H2b-ScgPtH1jajEpxgDHqdb-RKekQfgyNncsE8Y,2874
|
|
39
|
+
ezmsg/sigproc/slicer.py,sha256=xLXxWf722V08ytVwvPimYjDKKj0pkC2HjdgCVaoaOvs,5195
|
|
40
|
+
ezmsg/sigproc/spectral.py,sha256=wFzuihS7qJZMQcp0ds_qCG-zCbvh5DyhFRjn2wA9TWQ,322
|
|
41
|
+
ezmsg/sigproc/spectrogram.py,sha256=g8xYWENzle6O5uEF-vfjsF5gOSDnJTwiu3ZudicO470,2893
|
|
42
|
+
ezmsg/sigproc/spectrum.py,sha256=AAxrywIYpAPENRWvaaM2VjcKEaqMt6ra1E3Ao26jdZs,9523
|
|
43
|
+
ezmsg/sigproc/transpose.py,sha256=Yx4losN7tKCacUt2GmFvjOSqJ0b3XhEepXzq_Z_iMCI,4381
|
|
44
|
+
ezmsg/sigproc/wavelets.py,sha256=mN9TrZencyvKBfnuMiGZ_lzrE1O7DhVo05EYgCjXncg,7428
|
|
45
|
+
ezmsg/sigproc/window.py,sha256=ZlawY4TPbLc46qIgcKhP4X7dpMDo4zNlnfzgV1eFaGU,15335
|
|
46
|
+
ezmsg/sigproc/math/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
47
|
+
ezmsg/sigproc/math/abs.py,sha256=_omQP4baHGu8MgKzNDMUsjrmA_yeXWNqKyTU7BiHCSE,741
|
|
48
|
+
ezmsg/sigproc/math/add.py,sha256=lR4lB8-QdUfyARJcdf5sMQhbHtFpRNYt8_1zYzkVEhU,3659
|
|
49
|
+
ezmsg/sigproc/math/clip.py,sha256=vJ8zpzVlTVPlkElsqyPVMOwyKBrgym8RD8BEOvf8g1o,1131
|
|
50
|
+
ezmsg/sigproc/math/difference.py,sha256=TtAURz9TsW_Vk39sMJOT84P0xw0xDrgE3ToRi8MWVv4,4491
|
|
51
|
+
ezmsg/sigproc/math/invert.py,sha256=SYJDNEb7snkVODnItfkkp8rhMrHEdyBmzg6qZkZLX2c,630
|
|
52
|
+
ezmsg/sigproc/math/log.py,sha256=K8bZSm-ubTDY0oqwuc0IOMkdPIwpw1yysjTOG657kkQ,1488
|
|
53
|
+
ezmsg/sigproc/math/scale.py,sha256=Zpzlz1NSLyvmggjs0pPypUKgXX99z2S3VXJ06fHok5M,942
|
|
54
|
+
ezmsg/sigproc/util/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
55
|
+
ezmsg/sigproc/util/asio.py,sha256=aAj0e7OoBvkRy28k05HL2s9YPCTxOddc05xMN-qd4lQ,577
|
|
56
|
+
ezmsg/sigproc/util/axisarray_buffer.py,sha256=TGDeC6CXmmp7OUuiGd6xYQijRGYDE4QGdWxjK5Vs3nE,14057
|
|
57
|
+
ezmsg/sigproc/util/buffer.py,sha256=83Gm0IuowmcMlXgLFB_rz8_ZPhkwG4DNNejyWJDKJl8,19658
|
|
58
|
+
ezmsg/sigproc/util/message.py,sha256=ppN3IYtIAwrxWG9JOvgWFn1wDdIumkEzYFfqpH9VQkY,338
|
|
59
|
+
ezmsg/sigproc/util/profile.py,sha256=eVOo9pXgusrnH1yfRdd2RsM7Dbe2UpyC0LJ9MfGpB08,416
|
|
60
|
+
ezmsg/sigproc/util/sparse.py,sha256=NjbJitCtO0B6CENTlyd9c-lHEJwoCan-T3DIgPyeShw,4834
|
|
61
|
+
ezmsg/sigproc/util/typeresolution.py,sha256=fMFzLi63dqCIclGFLcMdM870OYxJnkeWw6aWKNMk718,362
|
|
62
|
+
ezmsg_sigproc-2.8.0.dist-info/METADATA,sha256=JZfuyxTvO6n3dIztHrFs531fF6agB_uKkPyXRMlW-EU,1908
|
|
63
|
+
ezmsg_sigproc-2.8.0.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
|
|
64
|
+
ezmsg_sigproc-2.8.0.dist-info/licenses/LICENSE,sha256=seu0tKhhAMPCUgc1XpXGGaCxY1YaYvFJwqFuQZAl2go,1100
|
|
65
|
+
ezmsg_sigproc-2.8.0.dist-info/RECORD,,
|