ezmsg-sigproc 1.3.2__py3-none-any.whl → 1.4.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.
- ezmsg/sigproc/__version__.py +2 -2
- ezmsg/sigproc/activation.py +12 -0
- ezmsg/sigproc/affinetransform.py +4 -5
- ezmsg/sigproc/aggregate.py +5 -1
- ezmsg/sigproc/bandpower.py +2 -1
- ezmsg/sigproc/base.py +2 -1
- ezmsg/sigproc/butterworthfilter.py +11 -7
- ezmsg/sigproc/downsample.py +3 -3
- ezmsg/sigproc/filter.py +7 -3
- ezmsg/sigproc/filterbank.py +6 -4
- ezmsg/sigproc/math/abs.py +7 -1
- ezmsg/sigproc/math/clip.py +12 -2
- ezmsg/sigproc/math/difference.py +9 -0
- ezmsg/sigproc/math/invert.py +8 -2
- ezmsg/sigproc/math/log.py +21 -2
- ezmsg/sigproc/math/scale.py +11 -2
- ezmsg/sigproc/sampler.py +1 -1
- ezmsg/sigproc/scaler.py +5 -6
- ezmsg/sigproc/signalinjector.py +5 -0
- ezmsg/sigproc/slicer.py +14 -1
- ezmsg/sigproc/spectrogram.py +7 -3
- ezmsg/sigproc/spectrum.py +2 -2
- ezmsg/sigproc/wavelets.py +5 -3
- ezmsg/sigproc/window.py +13 -6
- {ezmsg_sigproc-1.3.2.dist-info → ezmsg_sigproc-1.4.1.dist-info}/METADATA +1 -1
- ezmsg_sigproc-1.4.1.dist-info/RECORD +35 -0
- ezmsg_sigproc-1.3.2.dist-info/RECORD +0 -35
- {ezmsg_sigproc-1.3.2.dist-info → ezmsg_sigproc-1.4.1.dist-info}/WHEEL +0 -0
- {ezmsg_sigproc-1.3.2.dist-info → ezmsg_sigproc-1.4.1.dist-info}/licenses/LICENSE.txt +0 -0
ezmsg/sigproc/__version__.py
CHANGED
ezmsg/sigproc/activation.py
CHANGED
|
@@ -43,6 +43,18 @@ ACTIVATIONS = {
|
|
|
43
43
|
def activation(
|
|
44
44
|
function: typing.Union[str, ActivationFunction],
|
|
45
45
|
) -> typing.Generator[AxisArray, AxisArray, None]:
|
|
46
|
+
"""
|
|
47
|
+
Transform the data with a simple activation function.
|
|
48
|
+
|
|
49
|
+
Args:
|
|
50
|
+
function: An enum value from ActivationFunction or a string representing the activation function.
|
|
51
|
+
Possible values are: SIGMOID, EXPIT, LOGIT, LOGEXPIT, "sigmoid", "expit", "logit", "log_expit".
|
|
52
|
+
SIGMOID and EXPIT are equivalent. See :obj:`scipy.special.expit` for more details.
|
|
53
|
+
|
|
54
|
+
Returns: A primed generator that, when passed an input message via `.send(msg)`, yields an AxisArray
|
|
55
|
+
with the data payload containing a transformed version of the input data.
|
|
56
|
+
|
|
57
|
+
"""
|
|
46
58
|
if type(function) is ActivationFunction:
|
|
47
59
|
func = ACTIVATIONS[function]
|
|
48
60
|
else:
|
ezmsg/sigproc/affinetransform.py
CHANGED
|
@@ -24,7 +24,7 @@ def affine_transform(
|
|
|
24
24
|
Args:
|
|
25
25
|
weights: An array of weights or a path to a file with weights compatible with np.loadtxt.
|
|
26
26
|
axis: The name of the axis to apply the transformation to. Defaults to the leading (0th) axis in the array.
|
|
27
|
-
right_multiply: Set False to
|
|
27
|
+
right_multiply: Set False to transpose the weights before applying.
|
|
28
28
|
|
|
29
29
|
Returns:
|
|
30
30
|
A primed generator object that yields an :obj:`AxisArray` object for every
|
|
@@ -76,16 +76,15 @@ def affine_transform(
|
|
|
76
76
|
):
|
|
77
77
|
in_labels = msg_in.axes[axis].labels
|
|
78
78
|
new_labels = []
|
|
79
|
-
n_in = weights.shape
|
|
80
|
-
n_out = weights.shape[0 if right_multiply else 1]
|
|
79
|
+
n_in, n_out = weights.shape
|
|
81
80
|
if len(in_labels) != n_in:
|
|
82
81
|
# Something upstream did something it wasn't supposed to. We will drop the labels.
|
|
83
82
|
ez.logger.warning(
|
|
84
83
|
f"Received {len(in_labels)} for {n_in} inputs. Check upstream labels."
|
|
85
84
|
)
|
|
86
85
|
else:
|
|
87
|
-
|
|
88
|
-
|
|
86
|
+
b_filled_outputs = np.any(weights, axis=0)
|
|
87
|
+
b_used_inputs = np.any(weights, axis=1)
|
|
89
88
|
if np.all(b_used_inputs) and np.all(b_filled_outputs):
|
|
90
89
|
# All inputs are used and all outputs are used, but n_in != n_out.
|
|
91
90
|
# Mapping cannot be determined.
|
ezmsg/sigproc/aggregate.py
CHANGED
|
@@ -20,11 +20,13 @@ class AggregationFunction(OptionsEnum):
|
|
|
20
20
|
MEAN = "mean"
|
|
21
21
|
MEDIAN = "median"
|
|
22
22
|
STD = "std"
|
|
23
|
+
SUM = "sum"
|
|
23
24
|
NANMAX = "nanmax"
|
|
24
25
|
NANMIN = "nanmin"
|
|
25
26
|
NANMEAN = "nanmean"
|
|
26
27
|
NANMEDIAN = "nanmedian"
|
|
27
28
|
NANSTD = "nanstd"
|
|
29
|
+
NANSUM = "nansum"
|
|
28
30
|
ARGMIN = "argmin"
|
|
29
31
|
ARGMAX = "argmax"
|
|
30
32
|
|
|
@@ -36,11 +38,13 @@ AGGREGATORS = {
|
|
|
36
38
|
AggregationFunction.MEAN: np.mean,
|
|
37
39
|
AggregationFunction.MEDIAN: np.median,
|
|
38
40
|
AggregationFunction.STD: np.std,
|
|
41
|
+
AggregationFunction.SUM: np.sum,
|
|
39
42
|
AggregationFunction.NANMAX: np.nanmax,
|
|
40
43
|
AggregationFunction.NANMIN: np.nanmin,
|
|
41
44
|
AggregationFunction.NANMEAN: np.nanmean,
|
|
42
45
|
AggregationFunction.NANMEDIAN: np.nanmedian,
|
|
43
46
|
AggregationFunction.NANSTD: np.nanstd,
|
|
47
|
+
AggregationFunction.NANSUM: np.nansum,
|
|
44
48
|
AggregationFunction.ARGMIN: np.argmin,
|
|
45
49
|
AggregationFunction.ARGMAX: np.argmax,
|
|
46
50
|
}
|
|
@@ -62,7 +66,7 @@ def ranged_aggregate(
|
|
|
62
66
|
operation: :obj:`AggregationFunction` to apply to each band.
|
|
63
67
|
|
|
64
68
|
Returns:
|
|
65
|
-
A primed generator object ready to yield an AxisArray for each .send(axis_array)
|
|
69
|
+
A primed generator object ready to yield an :obj:`AxisArray` for each .send(axis_array)
|
|
66
70
|
"""
|
|
67
71
|
msg_out = AxisArray(np.array([]), dims=[""])
|
|
68
72
|
|
ezmsg/sigproc/bandpower.py
CHANGED
|
@@ -27,7 +27,8 @@ def bandpower(
|
|
|
27
27
|
bands: (min, max) tuples of band limits in Hz.
|
|
28
28
|
|
|
29
29
|
Returns:
|
|
30
|
-
A primed generator object ready to yield an AxisArray for each .send(axis_array)
|
|
30
|
+
A primed generator object ready to yield an :obj:`AxisArray` for each .send(axis_array)
|
|
31
|
+
with the data payload being the average spectral power in each band of the input data.
|
|
31
32
|
"""
|
|
32
33
|
msg_out = AxisArray(np.array([]), dims=[""])
|
|
33
34
|
|
ezmsg/sigproc/base.py
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import math
|
|
1
2
|
import traceback
|
|
2
3
|
import typing
|
|
3
4
|
|
|
@@ -30,7 +31,7 @@ class GenAxisArray(ez.Unit):
|
|
|
30
31
|
async def on_signal(self, message: AxisArray) -> typing.AsyncGenerator:
|
|
31
32
|
try:
|
|
32
33
|
ret = self.STATE.gen.send(message)
|
|
33
|
-
if ret.data.
|
|
34
|
+
if math.prod(ret.data.shape) > 0:
|
|
34
35
|
yield self.OUTPUT_SIGNAL, ret
|
|
35
36
|
except (StopIteration, GeneratorExit):
|
|
36
37
|
ez.logger.debug(f"Generator closed in {self.address}")
|
|
@@ -13,19 +13,22 @@ class ButterworthFilterSettings(FilterSettingsBase):
|
|
|
13
13
|
"""Settings for :obj:`ButterworthFilter`."""
|
|
14
14
|
|
|
15
15
|
order: int = 0
|
|
16
|
+
"""
|
|
17
|
+
Filter order
|
|
18
|
+
"""
|
|
16
19
|
|
|
17
20
|
cuton: typing.Optional[float] = None
|
|
18
21
|
"""
|
|
19
|
-
Cuton frequency (Hz). If cutoff is not specified then this is the highpass corner,
|
|
20
|
-
if
|
|
21
|
-
or if
|
|
22
|
+
Cuton frequency (Hz). If `cutoff` is not specified then this is the highpass corner. Otherwise,
|
|
23
|
+
if this is lower than `cutoff` then this is the beginning of the bandpass
|
|
24
|
+
or if this is greater than `cutoff` then this is the end of the bandstop.
|
|
22
25
|
"""
|
|
23
26
|
|
|
24
27
|
cutoff: typing.Optional[float] = None
|
|
25
28
|
"""
|
|
26
|
-
Cutoff frequency (Hz). If cuton is not specified then this is the lowpass corner,
|
|
27
|
-
if
|
|
28
|
-
or if
|
|
29
|
+
Cutoff frequency (Hz). If `cuton` is not specified then this is the lowpass corner. Otherwise,
|
|
30
|
+
if this is greater than `cuton` then this is the end of the bandpass,
|
|
31
|
+
or if this is less than `cuton` then this is the beginning of the bandstop.
|
|
29
32
|
"""
|
|
30
33
|
|
|
31
34
|
def filter_specs(
|
|
@@ -76,7 +79,8 @@ def butter(
|
|
|
76
79
|
coef_type: "ba" or "sos"
|
|
77
80
|
|
|
78
81
|
Returns:
|
|
79
|
-
A primed generator object which accepts .send(axis_array)
|
|
82
|
+
A primed generator object which accepts an :obj:`AxisArray` via .send(axis_array)
|
|
83
|
+
and yields an :obj:`AxisArray` with filtered data.
|
|
80
84
|
|
|
81
85
|
"""
|
|
82
86
|
# IO
|
ezmsg/sigproc/downsample.py
CHANGED
|
@@ -25,10 +25,10 @@ def downsample(
|
|
|
25
25
|
factor: Downsampling factor.
|
|
26
26
|
|
|
27
27
|
Returns:
|
|
28
|
-
A primed generator object ready to receive
|
|
29
|
-
and yields
|
|
28
|
+
A primed generator object ready to receive an :obj:`AxisArray` via `.send(axis_array)`
|
|
29
|
+
and yields an :obj:`AxisArray` with its data downsampled.
|
|
30
30
|
Note that if a send chunk does not have sufficient samples to reach the
|
|
31
|
-
next downsample interval then `
|
|
31
|
+
next downsample interval then an :obj:`AxisArray` with size-zero data is yielded.
|
|
32
32
|
|
|
33
33
|
"""
|
|
34
34
|
msg_out = AxisArray(np.array([]), dims=[""])
|
ezmsg/sigproc/filter.py
CHANGED
|
@@ -38,7 +38,7 @@ def filtergen(
|
|
|
38
38
|
axis: str, coefs: typing.Optional[typing.Tuple[np.ndarray]], coef_type: str
|
|
39
39
|
) -> typing.Generator[AxisArray, AxisArray, None]:
|
|
40
40
|
"""
|
|
41
|
-
|
|
41
|
+
Filter data using the provided coefficients.
|
|
42
42
|
|
|
43
43
|
Args:
|
|
44
44
|
axis: The name of the axis to operate on.
|
|
@@ -46,7 +46,8 @@ def filtergen(
|
|
|
46
46
|
coef_type: The type of filter coefficients. One of "ba" or "sos".
|
|
47
47
|
|
|
48
48
|
Returns:
|
|
49
|
-
A generator that
|
|
49
|
+
A primed generator that, when passed an :obj:`AxisArray` via `.send(axis_array)`,
|
|
50
|
+
yields an :obj:`AxisArray` with the data filtered.
|
|
50
51
|
"""
|
|
51
52
|
# Massage inputs
|
|
52
53
|
if coefs is not None and not isinstance(coefs, tuple):
|
|
@@ -97,7 +98,10 @@ def filtergen(
|
|
|
97
98
|
n_tile = (1,) + n_tile
|
|
98
99
|
zi = np.tile(zi[zi_expand], n_tile)
|
|
99
100
|
|
|
100
|
-
|
|
101
|
+
if msg_in.data.size > 0:
|
|
102
|
+
dat_out, zi = filt_func(*coefs, msg_in.data, axis=axis_idx, zi=zi)
|
|
103
|
+
else:
|
|
104
|
+
dat_out = msg_in.data
|
|
101
105
|
msg_out = replace(msg_in, data=dat_out)
|
|
102
106
|
|
|
103
107
|
|
ezmsg/sigproc/filterbank.py
CHANGED
|
@@ -43,9 +43,9 @@ def filterbank(
|
|
|
43
43
|
new_axis: str = "kernel",
|
|
44
44
|
) -> typing.Generator[AxisArray, AxisArray, None]:
|
|
45
45
|
"""
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
46
|
+
Perform multiple (direct or fft) convolutions on a signal using a bank of kernels.
|
|
47
|
+
This is intended to be used during online processing, therefore both direct and fft convolutions
|
|
48
|
+
use the overlap-add method.
|
|
49
49
|
Args:
|
|
50
50
|
kernels:
|
|
51
51
|
mode: "conv", "fft", or "auto". If "auto", the mode is determined by the size of the input data.
|
|
@@ -59,7 +59,8 @@ def filterbank(
|
|
|
59
59
|
axis: The name of the axis to operate on. This should usually be "time".
|
|
60
60
|
new_axis: The name of the new axis corresponding to the kernel index.
|
|
61
61
|
|
|
62
|
-
Returns:
|
|
62
|
+
Returns: A primed generator that, when passed an input message via `.send(msg)`, yields an :obj:`AxisArray`
|
|
63
|
+
with the data payload containing the absolute value of the input :obj:`AxisArray` data.
|
|
63
64
|
|
|
64
65
|
"""
|
|
65
66
|
msg_out: typing.Optional[AxisArray] = None
|
|
@@ -133,6 +134,7 @@ def filterbank(
|
|
|
133
134
|
+ msg_in.dims[targ_ax_ix + 1 :]
|
|
134
135
|
+ [new_axis, axis],
|
|
135
136
|
axes=msg_in.axes.copy(), # We do not have info for kernel/filter axis :(.
|
|
137
|
+
key=msg_in.key,
|
|
136
138
|
)
|
|
137
139
|
|
|
138
140
|
# Determine optimal mode. Assumes 100 msec chunks.
|
ezmsg/sigproc/math/abs.py
CHANGED
|
@@ -11,9 +11,15 @@ from ..base import GenAxisArray
|
|
|
11
11
|
|
|
12
12
|
@consumer
|
|
13
13
|
def abs() -> typing.Generator[AxisArray, AxisArray, None]:
|
|
14
|
+
"""
|
|
15
|
+
Take the absolute value of the data. See :obj:`np.abs` for more details.
|
|
16
|
+
|
|
17
|
+
Returns: A primed generator that, when passed an input message via `.send(msg)`, yields an :obj:`AxisArray`
|
|
18
|
+
with the data payload containing the absolute value of the input :obj:`AxisArray` data.
|
|
19
|
+
"""
|
|
14
20
|
msg_out = AxisArray(np.array([]), dims=[""])
|
|
15
21
|
while True:
|
|
16
|
-
msg_in = yield msg_out
|
|
22
|
+
msg_in: AxisArray = yield msg_out
|
|
17
23
|
msg_out = replace(msg_in, data=np.abs(msg_in.data))
|
|
18
24
|
|
|
19
25
|
|
ezmsg/sigproc/math/clip.py
CHANGED
|
@@ -11,10 +11,20 @@ from ..base import GenAxisArray
|
|
|
11
11
|
|
|
12
12
|
@consumer
|
|
13
13
|
def clip(a_min: float, a_max: float) -> typing.Generator[AxisArray, AxisArray, None]:
|
|
14
|
-
|
|
14
|
+
"""
|
|
15
|
+
Clips the data to be within the specified range. See :obj:`np.clip` for more details.
|
|
16
|
+
|
|
17
|
+
Args:
|
|
18
|
+
a_min: Lower clip bound
|
|
19
|
+
a_max: Upper clip bound
|
|
20
|
+
|
|
21
|
+
Returns: A primed generator that, when passed an input message via `.send(msg)`, yields an :obj:`AxisArray`
|
|
22
|
+
with the data payload containing the clipped version of the input :obj:`AxisArray` data.
|
|
23
|
+
|
|
24
|
+
"""
|
|
15
25
|
msg_out = AxisArray(np.array([]), dims=[""])
|
|
16
26
|
while True:
|
|
17
|
-
msg_in = yield msg_out
|
|
27
|
+
msg_in: AxisArray = yield msg_out
|
|
18
28
|
msg_out = replace(msg_in, data=np.clip(msg_in.data, a_min, a_max))
|
|
19
29
|
|
|
20
30
|
|
ezmsg/sigproc/math/difference.py
CHANGED
|
@@ -16,6 +16,15 @@ def const_difference(
|
|
|
16
16
|
"""
|
|
17
17
|
result = (in_data - value) if subtrahend else (value - in_data)
|
|
18
18
|
https://en.wikipedia.org/wiki/Template:Arithmetic_operations
|
|
19
|
+
|
|
20
|
+
Args:
|
|
21
|
+
value: number to subtract or be subtracted from the input data
|
|
22
|
+
subtrahend: If True (default) then value is subtracted from the input data.
|
|
23
|
+
If False, the input data is subtracted from value.
|
|
24
|
+
|
|
25
|
+
Returns: A primed generator that, when passed an input message via `.send(msg)`, yields an :obj:`AxisArray`
|
|
26
|
+
with the data payload containing the difference between the input :obj:`AxisArray` data and the value.
|
|
27
|
+
|
|
19
28
|
"""
|
|
20
29
|
msg_out = AxisArray(np.array([]), dims=[""])
|
|
21
30
|
while True:
|
ezmsg/sigproc/math/invert.py
CHANGED
|
@@ -11,10 +11,16 @@ from ..base import GenAxisArray
|
|
|
11
11
|
|
|
12
12
|
@consumer
|
|
13
13
|
def invert() -> typing.Generator[AxisArray, AxisArray, None]:
|
|
14
|
-
|
|
14
|
+
"""
|
|
15
|
+
Take the inverse of the data.
|
|
16
|
+
|
|
17
|
+
Returns: A primed generator that, when passed an input message via `.send(msg)`, yields an :obj:`AxisArray`
|
|
18
|
+
with the data payload containing the inversion of the input :obj:`AxisArray` data.
|
|
19
|
+
|
|
20
|
+
"""
|
|
15
21
|
msg_out = AxisArray(np.array([]), dims=[""])
|
|
16
22
|
while True:
|
|
17
|
-
msg_in = yield msg_out
|
|
23
|
+
msg_in: AxisArray = yield msg_out
|
|
18
24
|
msg_out = replace(msg_in, data=1 / msg_in.data)
|
|
19
25
|
|
|
20
26
|
|
ezmsg/sigproc/math/log.py
CHANGED
|
@@ -12,12 +12,31 @@ from ..base import GenAxisArray
|
|
|
12
12
|
@consumer
|
|
13
13
|
def log(
|
|
14
14
|
base: float = 10.0,
|
|
15
|
+
clip_zero: bool = False,
|
|
15
16
|
) -> typing.Generator[AxisArray, AxisArray, None]:
|
|
16
|
-
|
|
17
|
+
"""
|
|
18
|
+
Take the logarithm of the data. See :obj:`np.log` for more details.
|
|
19
|
+
|
|
20
|
+
Args:
|
|
21
|
+
base: The base of the logarithm. Default is 10.
|
|
22
|
+
clip_zero: If True, clip the data to the minimum positive value of the data type before taking the log.
|
|
23
|
+
|
|
24
|
+
Returns: A primed generator that, when passed an input message via `.send(msg)`, yields an :obj:`AxisArray`
|
|
25
|
+
with the data payload containing the logarithm of the input :obj:`AxisArray` data.
|
|
26
|
+
|
|
27
|
+
"""
|
|
17
28
|
msg_out = AxisArray(np.array([]), dims=[""])
|
|
18
29
|
log_base = np.log(base)
|
|
19
30
|
while True:
|
|
20
|
-
msg_in = yield msg_out
|
|
31
|
+
msg_in: AxisArray = yield msg_out
|
|
32
|
+
if (
|
|
33
|
+
clip_zero
|
|
34
|
+
and np.any(msg_in.data <= 0)
|
|
35
|
+
and np.issubdtype(msg_in.data.dtype, np.floating)
|
|
36
|
+
):
|
|
37
|
+
msg_in.data = np.clip(
|
|
38
|
+
msg_in.data, a_min=np.finfo(msg_in.data.dtype).tiny, a_max=None
|
|
39
|
+
)
|
|
21
40
|
msg_out = replace(msg_in, data=np.log(msg_in.data) / log_base)
|
|
22
41
|
|
|
23
42
|
|
ezmsg/sigproc/math/scale.py
CHANGED
|
@@ -11,10 +11,19 @@ from ..base import GenAxisArray
|
|
|
11
11
|
|
|
12
12
|
@consumer
|
|
13
13
|
def scale(scale: float = 1.0) -> typing.Generator[AxisArray, AxisArray, None]:
|
|
14
|
-
|
|
14
|
+
"""
|
|
15
|
+
Scale the data by a constant factor.
|
|
16
|
+
|
|
17
|
+
Args:
|
|
18
|
+
scale: Factor by which to scale the data magnitude.
|
|
19
|
+
|
|
20
|
+
Returns: A primed generator that, when passed an input message via `.send(msg)`, yields an :obj:`AxisArray`
|
|
21
|
+
with the data payload containing the input :obj:`AxisArray` data scaled by a constant factor.
|
|
22
|
+
|
|
23
|
+
"""
|
|
15
24
|
msg_out = AxisArray(np.array([]), dims=[""])
|
|
16
25
|
while True:
|
|
17
|
-
msg_in = yield msg_out
|
|
26
|
+
msg_in: AxisArray = yield msg_out
|
|
18
27
|
msg_out = replace(msg_in, data=scale * msg_in.data)
|
|
19
28
|
|
|
20
29
|
|
ezmsg/sigproc/sampler.py
CHANGED
|
@@ -43,7 +43,7 @@ def sampler(
|
|
|
43
43
|
typing.List[SampleMessage], typing.Union[AxisArray, SampleTriggerMessage], None
|
|
44
44
|
]:
|
|
45
45
|
"""
|
|
46
|
-
|
|
46
|
+
Sample data into a buffer, accept triggers, and return slices of sampled
|
|
47
47
|
data around the trigger time.
|
|
48
48
|
|
|
49
49
|
Args:
|
ezmsg/sigproc/scaler.py
CHANGED
|
@@ -33,8 +33,7 @@ def scaler(
|
|
|
33
33
|
time_constant: float = 1.0, axis: typing.Optional[str] = None
|
|
34
34
|
) -> typing.Generator[AxisArray, AxisArray, None]:
|
|
35
35
|
"""
|
|
36
|
-
|
|
37
|
-
adaptive standard scaler from https://riverml.xyz/latest/api/preprocessing/AdaptiveStandardScaler/
|
|
36
|
+
Apply the adaptive standard scaler from https://riverml.xyz/latest/api/preprocessing/AdaptiveStandardScaler/
|
|
38
37
|
This is faster than :obj:`scaler_np` for single-channel data.
|
|
39
38
|
|
|
40
39
|
Args:
|
|
@@ -42,8 +41,8 @@ def scaler(
|
|
|
42
41
|
axis: The name of the axis to accumulate statistics over.
|
|
43
42
|
|
|
44
43
|
Returns:
|
|
45
|
-
A primed generator object that expects `.send(axis_array)`
|
|
46
|
-
|
|
44
|
+
A primed generator object that expects to be sent a :obj:`AxisArray` via `.send(axis_array)`
|
|
45
|
+
and yields an :obj:`AxisArray` with its data being a standardized, or "Z-scored" version of the input data.
|
|
47
46
|
"""
|
|
48
47
|
from river import preprocessing
|
|
49
48
|
|
|
@@ -90,8 +89,8 @@ def scaler_np(
|
|
|
90
89
|
axis: The name of the axis to accumulate statistics over.
|
|
91
90
|
|
|
92
91
|
Returns:
|
|
93
|
-
A primed generator object that expects `.send(axis_array)`
|
|
94
|
-
|
|
92
|
+
A primed generator object that expects to be sent a :obj:`AxisArray` via `.send(axis_array)`
|
|
93
|
+
and yields an :obj:`AxisArray` with its data being a standardized, or "Z-scored" version of the input data.
|
|
95
94
|
"""
|
|
96
95
|
msg_out = AxisArray(np.array([]), dims=[""])
|
|
97
96
|
|
ezmsg/sigproc/signalinjector.py
CHANGED
|
@@ -22,6 +22,11 @@ class SignalInjectorState(ez.State):
|
|
|
22
22
|
|
|
23
23
|
|
|
24
24
|
class SignalInjector(ez.Unit):
|
|
25
|
+
"""
|
|
26
|
+
Add a sinusoidal signal to the input signal. Each feature gets a different amplitude of the sinusoid.
|
|
27
|
+
All features get the same frequency sinusoid. The frequency and base amplitude can be changed while running.
|
|
28
|
+
"""
|
|
29
|
+
|
|
25
30
|
SETTINGS = SignalInjectorSettings
|
|
26
31
|
STATE = SignalInjectorState
|
|
27
32
|
|
ezmsg/sigproc/slicer.py
CHANGED
|
@@ -48,6 +48,18 @@ def parse_slice(s: str) -> typing.Tuple[typing.Union[slice, int], ...]:
|
|
|
48
48
|
def slicer(
|
|
49
49
|
selection: str = "", axis: typing.Optional[str] = None
|
|
50
50
|
) -> typing.Generator[AxisArray, AxisArray, None]:
|
|
51
|
+
"""
|
|
52
|
+
Slice along a particular axis.
|
|
53
|
+
|
|
54
|
+
Args:
|
|
55
|
+
selection: See :obj:`ezmsg.sigproc.slicer.parse_slice` for details.
|
|
56
|
+
axis: The name of the axis to slice along. If None, the last axis is used.
|
|
57
|
+
|
|
58
|
+
Returns:
|
|
59
|
+
A primed generator object ready to yield an :obj:`AxisArray` for each .send(axis_array)
|
|
60
|
+
with the data payload containing a sliced view of the input data.
|
|
61
|
+
|
|
62
|
+
"""
|
|
51
63
|
msg_out = AxisArray(np.array([]), dims=[""])
|
|
52
64
|
|
|
53
65
|
# State variables
|
|
@@ -98,7 +110,8 @@ def slicer(
|
|
|
98
110
|
and hasattr(msg_in.axes[axis], "labels")
|
|
99
111
|
and len(msg_in.axes[axis].labels) > 0
|
|
100
112
|
):
|
|
101
|
-
|
|
113
|
+
in_labels = np.array(msg_in.axes[axis].labels)
|
|
114
|
+
new_labels = in_labels[_slice].tolist()
|
|
102
115
|
new_axis = replace(msg_in.axes[axis], labels=new_labels)
|
|
103
116
|
|
|
104
117
|
replace_kwargs = {}
|
ezmsg/sigproc/spectrogram.py
CHANGED
|
@@ -33,13 +33,17 @@ def spectrogram(
|
|
|
33
33
|
output: See :obj:`ezmsg.sigproc.spectrum.spectrum`
|
|
34
34
|
|
|
35
35
|
Returns:
|
|
36
|
-
A primed generator object that expects `.send(axis_array)`
|
|
37
|
-
and yields an AxisArray of time-frequency power values.
|
|
36
|
+
A primed generator object that expects an :obj:`AxisArray` via `.send(axis_array)`
|
|
37
|
+
with continuous data in its .data payload, and yields an :obj:`AxisArray` of time-frequency power values.
|
|
38
38
|
"""
|
|
39
39
|
|
|
40
40
|
pipeline = compose(
|
|
41
41
|
windowing(
|
|
42
|
-
axis="time",
|
|
42
|
+
axis="time",
|
|
43
|
+
newaxis="win",
|
|
44
|
+
window_dur=window_dur,
|
|
45
|
+
window_shift=window_shift,
|
|
46
|
+
zero_pad_until="shift" if window_shift is not None else "input",
|
|
43
47
|
),
|
|
44
48
|
spectrum(axis="time", window=window, transform=transform, output=output),
|
|
45
49
|
modify_axis(name_map={"win": "time"}),
|
ezmsg/sigproc/spectrum.py
CHANGED
|
@@ -92,8 +92,8 @@ def spectrum(
|
|
|
92
92
|
nfft: The number of points to use for the FFT. If None, the length of the input data is used.
|
|
93
93
|
|
|
94
94
|
Returns:
|
|
95
|
-
A primed generator object that expects `.send(axis_array)`
|
|
96
|
-
and yields an AxisArray of spectral magnitudes or powers.
|
|
95
|
+
A primed generator object that expects an :obj:`AxisArray` via `.send(axis_array)` containing continuous data
|
|
96
|
+
and yields an :obj:`AxisArray` with data of spectral magnitudes or powers.
|
|
97
97
|
"""
|
|
98
98
|
msg_out = AxisArray(np.array([]), dims=[""])
|
|
99
99
|
|
ezmsg/sigproc/wavelets.py
CHANGED
|
@@ -20,8 +20,8 @@ def cwt(
|
|
|
20
20
|
axis: str = "time",
|
|
21
21
|
) -> typing.Generator[AxisArray, AxisArray, None]:
|
|
22
22
|
"""
|
|
23
|
-
|
|
24
|
-
The function is equivalent to the
|
|
23
|
+
Perform a continuous wavelet transform.
|
|
24
|
+
The function is equivalent to the :obj:`pywt.cwt` function, but is designed to work with streaming data.
|
|
25
25
|
|
|
26
26
|
Args:
|
|
27
27
|
scales: The wavelet scales to use.
|
|
@@ -31,7 +31,8 @@ def cwt(
|
|
|
31
31
|
because fft and matrix multiplication is much faster on the last axis.
|
|
32
32
|
|
|
33
33
|
Returns:
|
|
34
|
-
A Generator object that expects `.send(axis_array)` of continuous data
|
|
34
|
+
A primed Generator object that expects an :obj:`AxisArray` via `.send(axis_array)` of continuous data
|
|
35
|
+
and yields an :obj:`AxisArray` with a continuous wavelet transform in its data.
|
|
35
36
|
"""
|
|
36
37
|
msg_out: typing.Optional[AxisArray] = None
|
|
37
38
|
|
|
@@ -114,6 +115,7 @@ def cwt(
|
|
|
114
115
|
**msg_in.axes,
|
|
115
116
|
"freq": AxisArray.Axis("Hz", offset=freqs[0], gain=fstep),
|
|
116
117
|
},
|
|
118
|
+
key=msg_in.key,
|
|
117
119
|
)
|
|
118
120
|
last_conv_samp = np.zeros(
|
|
119
121
|
dummy_shape[:-1] + (1,), dtype=template.data.dtype
|
ezmsg/sigproc/window.py
CHANGED
|
@@ -24,7 +24,9 @@ def windowing(
|
|
|
24
24
|
zero_pad_until: str = "input",
|
|
25
25
|
) -> typing.Generator[AxisArray, AxisArray, None]:
|
|
26
26
|
"""
|
|
27
|
-
|
|
27
|
+
Apply a sliding window along the specified axis to input streaming data.
|
|
28
|
+
The `windowing` method is perhaps the most useful and versatile method in ezmsg.sigproc, but its parameterization
|
|
29
|
+
can be difficult. Please read the argument descriptions carefully.
|
|
28
30
|
|
|
29
31
|
Args:
|
|
30
32
|
axis: The axis along which to segment windows.
|
|
@@ -48,8 +50,8 @@ def windowing(
|
|
|
48
50
|
- "none" does not pad the buffer. No outputs will be yielded until at least `window_dur` data has been seen.
|
|
49
51
|
|
|
50
52
|
Returns:
|
|
51
|
-
A
|
|
52
|
-
|
|
53
|
+
A primed generator that accepts an :obj:`AxisArray` via `.send(axis_array)`
|
|
54
|
+
and yields an :obj:`AxisArray` with the data payload containing a windowed version of the input data.
|
|
53
55
|
"""
|
|
54
56
|
# Check arguments
|
|
55
57
|
if newaxis is None:
|
|
@@ -77,7 +79,7 @@ def windowing(
|
|
|
77
79
|
b_1to1 = window_shift is None
|
|
78
80
|
newaxis_warned: bool = b_1to1
|
|
79
81
|
out_newaxis: typing.Optional[AxisArray.Axis] = None
|
|
80
|
-
out_dims: typing.
|
|
82
|
+
out_dims: typing.Optional[typing.List[str]] = None
|
|
81
83
|
|
|
82
84
|
check_inputs = {"samp_shape": None, "fs": None, "key": None}
|
|
83
85
|
|
|
@@ -123,11 +125,12 @@ def windowing(
|
|
|
123
125
|
else: # i.e. zero_pad_until == "input"
|
|
124
126
|
req_samples = msg_in.data.shape[axis_idx]
|
|
125
127
|
n_zero = max(0, window_samples - req_samples)
|
|
126
|
-
|
|
128
|
+
init_buffer_shape = (
|
|
127
129
|
msg_in.data.shape[:axis_idx]
|
|
128
130
|
+ (n_zero,)
|
|
129
131
|
+ msg_in.data.shape[axis_idx + 1 :]
|
|
130
132
|
)
|
|
133
|
+
buffer = np.zeros(init_buffer_shape, dtype=msg_in.data.dtype)
|
|
131
134
|
|
|
132
135
|
# Add new data to buffer.
|
|
133
136
|
# Currently, we concatenate the new time samples and clip the output.
|
|
@@ -174,10 +177,14 @@ def windowing(
|
|
|
174
177
|
if b_1to1:
|
|
175
178
|
# one-to-one mode -- Each send yields exactly one window containing only the most recent samples.
|
|
176
179
|
buffer = slice_along_axis(buffer, slice(-window_samples, None), axis_idx)
|
|
177
|
-
out_dat =
|
|
180
|
+
out_dat = buffer.reshape(
|
|
181
|
+
buffer.shape[:axis_idx] + (1,) + buffer.shape[axis_idx:]
|
|
182
|
+
)
|
|
178
183
|
out_newaxis = replace(out_newaxis, offset=buffer_offset[-window_samples])
|
|
179
184
|
elif buffer.shape[axis_idx] >= window_samples:
|
|
180
185
|
# Deterministic window shifts.
|
|
186
|
+
# Note: After https://github.com/ezmsg-org/ezmsg/pull/152, add `window_shift_samples` as the last arg
|
|
187
|
+
# to `sliding_win_oneaxis` and remove the call to `slice_along_axis`.
|
|
181
188
|
out_dat = sliding_win_oneaxis(buffer, window_samples, axis_idx)
|
|
182
189
|
out_dat = slice_along_axis(
|
|
183
190
|
out_dat, slice(None, None, window_shift_samples), axis_idx
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.3
|
|
2
2
|
Name: ezmsg-sigproc
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.4.1
|
|
4
4
|
Summary: Timeseries signal processing implementations in ezmsg
|
|
5
5
|
Author-email: Griffin Milsap <griffin.milsap@gmail.com>, Preston Peranich <pperanich@gmail.com>, Chadwick Boulay <chadwick.boulay@gmail.com>
|
|
6
6
|
License-Expression: MIT
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
ezmsg/sigproc/__init__.py,sha256=8K4IcOA3-pfzadoM6s2Sfg5460KlJUocGgyTJTJl96U,52
|
|
2
|
+
ezmsg/sigproc/__version__.py,sha256=oFZsPxoSsCY6D2DiWMSueNvMDRRQN5ssWrPdQtlLJ_o,411
|
|
3
|
+
ezmsg/sigproc/activation.py,sha256=amvVjO-1BcChgK0VQi44i7-Tmz_2FK1xb-BTC52_DO0,2642
|
|
4
|
+
ezmsg/sigproc/affinetransform.py,sha256=a5xt6LSymlV3gNSdCjWdtUoi9kOkWiYx6oeiGEIphYI,8802
|
|
5
|
+
ezmsg/sigproc/aggregate.py,sha256=Wnvz1xXDQhdVkTfVPOmhdmjgIhR_YQhioo8Dwh4BaoE,5615
|
|
6
|
+
ezmsg/sigproc/bandpower.py,sha256=QPktf3v7sojDHhwUVcK3UNPU-Dm4sf2QQw3qmYWZ1r0,2228
|
|
7
|
+
ezmsg/sigproc/base.py,sha256=vut0BLjgc0mxYRbs7tDd9XzwRFA2_GcsgXZmIYovR0Y,1248
|
|
8
|
+
ezmsg/sigproc/butterworthfilter.py,sha256=vTESZAAcQhWLI8yIMOApsGAYgjv2ekCZsTIliFjEkc8,5345
|
|
9
|
+
ezmsg/sigproc/decimate.py,sha256=zNxJXauE4Z54Yy7tpN9_oJuW0I0ppQRWhSpwb3Ri2gc,1473
|
|
10
|
+
ezmsg/sigproc/downsample.py,sha256=0TOhWkg7B9g3FDcewHINZiNuo28JyXRtgTYvZ7C8ImM,3384
|
|
11
|
+
ezmsg/sigproc/ewmfilter.py,sha256=XzTmouRa7AnPjTiI32-oumwm4ZfOl6uPPUSldExNpAs,4516
|
|
12
|
+
ezmsg/sigproc/filter.py,sha256=x3ytFowxg4O0QFQeMDFmQieV86H-6Q3Mkt3ThRIOh60,8301
|
|
13
|
+
ezmsg/sigproc/filterbank.py,sha256=Rhs7AKWy36lrMlzftEbYPXPW-FwZZ-QUCEp_QFG9mFU,12443
|
|
14
|
+
ezmsg/sigproc/messages.py,sha256=KpYCWWRD5itVAq0-Lf8qd7ErEE1A9qdm2p7O8Y4zEFA,955
|
|
15
|
+
ezmsg/sigproc/sampler.py,sha256=Zv5eq9CLpE8ui4HyZzBEqxwqBf--IbexS7zBx3qKp3w,12733
|
|
16
|
+
ezmsg/sigproc/scaler.py,sha256=2Hi4XWWvUtPOVOfIyX0Dr0cZEdbTobZOoMXKh9Vszlk,5944
|
|
17
|
+
ezmsg/sigproc/signalinjector.py,sha256=T1yvigk9WYujYqubd15UAF6hNmSqS9J7rCzaPYENoEA,2644
|
|
18
|
+
ezmsg/sigproc/slicer.py,sha256=ffawSqhO06lC5TXg_Ujg0eP2EuF98McQiUdlwxn3psI,5072
|
|
19
|
+
ezmsg/sigproc/spectral.py,sha256=_2qO6as4Nesmc9V1WW2EXNMH5pPz8aVTEcIPOi4-g2o,322
|
|
20
|
+
ezmsg/sigproc/spectrogram.py,sha256=16By4VWln7UvZ8IV_TdNAFaJDgkzvVKXWpnsoZoiW1M,3146
|
|
21
|
+
ezmsg/sigproc/spectrum.py,sha256=a75d6q6o3dAuqX6ZuFv6AfHYDOMuhA01OVCugzFMUSQ,9415
|
|
22
|
+
ezmsg/sigproc/synth.py,sha256=ygJRI9Seqhrg13lUhcA6XSpxcEr3LL1NupviSQLrC9o,18351
|
|
23
|
+
ezmsg/sigproc/wavelets.py,sha256=_3jI52NzksD1WNnHx03F2p4V2uGN_MtBbLsJGRjeyoE,6596
|
|
24
|
+
ezmsg/sigproc/window.py,sha256=A697XG2YyR9ywmzfxJIXovi6wPwDhBI9UUeShNJFKgM,13094
|
|
25
|
+
ezmsg/sigproc/math/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
26
|
+
ezmsg/sigproc/math/abs.py,sha256=hqS_sbLqAKSlguj3_rsfeWzOe6233tMxXfjDPg1fi2g,918
|
|
27
|
+
ezmsg/sigproc/math/clip.py,sha256=xIfc6fEfiNh7ILG3IYxcuCd5VBqmWXmDliGi_dKVJpM,1131
|
|
28
|
+
ezmsg/sigproc/math/difference.py,sha256=s3al1WzUZXsG2XYzOprRcKP-VD9J5FwYx578_SKG0vg,2183
|
|
29
|
+
ezmsg/sigproc/math/invert.py,sha256=H8df1u8OVb5TOkRC8p5EW7R17kHdLOYqXVH_axy5bkI,882
|
|
30
|
+
ezmsg/sigproc/math/log.py,sha256=1wuPvdjiI29tC_gRSntfpAebJ0rDhlapyLjG5QwXRpo,1496
|
|
31
|
+
ezmsg/sigproc/math/scale.py,sha256=iIQuJAr5pzCiMqzi2YdzLc1agQBKBOcngdNZlLO3X_o,1050
|
|
32
|
+
ezmsg_sigproc-1.4.1.dist-info/METADATA,sha256=ba6ETetMm_XUgNkyMcGTgeVItvVZWd9QEzPpYkh0e3s,2376
|
|
33
|
+
ezmsg_sigproc-1.4.1.dist-info/WHEEL,sha256=1yFddiXMmvYK7QYTqtRNtX66WJ0Mz8PYEiEUoOUUxRY,87
|
|
34
|
+
ezmsg_sigproc-1.4.1.dist-info/licenses/LICENSE.txt,sha256=seu0tKhhAMPCUgc1XpXGGaCxY1YaYvFJwqFuQZAl2go,1100
|
|
35
|
+
ezmsg_sigproc-1.4.1.dist-info/RECORD,,
|
|
@@ -1,35 +0,0 @@
|
|
|
1
|
-
ezmsg/sigproc/__init__.py,sha256=8K4IcOA3-pfzadoM6s2Sfg5460KlJUocGgyTJTJl96U,52
|
|
2
|
-
ezmsg/sigproc/__version__.py,sha256=ik9WUFYTvRcmzFEUSqkI2H_62uw0XFdUT3mTLq8-_RY,411
|
|
3
|
-
ezmsg/sigproc/activation.py,sha256=-KgDSVmgYx8QhHM5UQHkMN6rHudeasuWOYhmM2_aWH0,2068
|
|
4
|
-
ezmsg/sigproc/affinetransform.py,sha256=pJlg07sXf-o-Rv-pSD1_M_kH0xWBM9vYKGcJ7HCGndU,8938
|
|
5
|
-
ezmsg/sigproc/aggregate.py,sha256=8kVs2S2MUuTZkRwn-vh4utv8uoWwWrIkgalxcBdT39M,5490
|
|
6
|
-
ezmsg/sigproc/bandpower.py,sha256=l_R_qcrRTLGYjg40VAinIHz24pdwET4AS4RXd2Ctcig,2126
|
|
7
|
-
ezmsg/sigproc/base.py,sha256=VtlneWR0GAsWzAfqMzFy-WYPbeF8C3qVenqj7h_Cfek,1224
|
|
8
|
-
ezmsg/sigproc/butterworthfilter.py,sha256=busvcDtVJx2ZHgenM4o0SDTeBbtXbPEXrClCRty0iF0,5233
|
|
9
|
-
ezmsg/sigproc/decimate.py,sha256=zNxJXauE4Z54Yy7tpN9_oJuW0I0ppQRWhSpwb3Ri2gc,1473
|
|
10
|
-
ezmsg/sigproc/downsample.py,sha256=Zuk_sCTk3eYOmyVsKGk9P6s-yUkfim_neBBc61ZVUKY,3304
|
|
11
|
-
ezmsg/sigproc/ewmfilter.py,sha256=XzTmouRa7AnPjTiI32-oumwm4ZfOl6uPPUSldExNpAs,4516
|
|
12
|
-
ezmsg/sigproc/filter.py,sha256=DHF-4CvxhNCGaAuVpn64wCxYuq5TpMH7bi0KKQNaOk0,8161
|
|
13
|
-
ezmsg/sigproc/filterbank.py,sha256=K3Y2SJ7kfEp-CiNNSgzEM7sq1hbYaXOvufKSVyYnUEw,12252
|
|
14
|
-
ezmsg/sigproc/messages.py,sha256=KpYCWWRD5itVAq0-Lf8qd7ErEE1A9qdm2p7O8Y4zEFA,955
|
|
15
|
-
ezmsg/sigproc/sampler.py,sha256=3-O5nplutDcojb0CCbkTQsH8cZ8yKxqYts_02LryIKM,12762
|
|
16
|
-
ezmsg/sigproc/scaler.py,sha256=eQuF3DL4NvxuEBjDgf2k4qqoctw5hIS_NIOfbOjOY0k,5823
|
|
17
|
-
ezmsg/sigproc/signalinjector.py,sha256=HzQvI6jvkuX7miGHy6h0yXVRz_wvM3ecpQvquCV0H7g,2408
|
|
18
|
-
ezmsg/sigproc/slicer.py,sha256=TcTI464UH9y1abCwT6eEMaqo7B1geuwJNNYScMUyyFM,4609
|
|
19
|
-
ezmsg/sigproc/spectral.py,sha256=_2qO6as4Nesmc9V1WW2EXNMH5pPz8aVTEcIPOi4-g2o,322
|
|
20
|
-
ezmsg/sigproc/spectrogram.py,sha256=osaqIhC04RbMnpHy5ecAxnYhQOn022oTvF2wbz-lKec,2977
|
|
21
|
-
ezmsg/sigproc/spectrum.py,sha256=AmoPObVVvuXkUSClCExvKzLoasLyTlIwtRsrz1XFOLI,9366
|
|
22
|
-
ezmsg/sigproc/synth.py,sha256=ygJRI9Seqhrg13lUhcA6XSpxcEr3LL1NupviSQLrC9o,18351
|
|
23
|
-
ezmsg/sigproc/wavelets.py,sha256=sccj7xsIyHmsUL7XWYm7wxnNvIGEcpCZ8qsfRXSObiA,6488
|
|
24
|
-
ezmsg/sigproc/window.py,sha256=bzOJDQRxDfcHNHrTgWkILGH9uYk4z0jy-JkCb8zguFQ,12599
|
|
25
|
-
ezmsg/sigproc/math/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
26
|
-
ezmsg/sigproc/math/abs.py,sha256=8rtcdyMSGtnMQgGwbcW8Ky-3uRspkYD7lRdpcFl6uEE,608
|
|
27
|
-
ezmsg/sigproc/math/clip.py,sha256=WBKe6wPTcqb041OwuUB5OGK-s_R3gc95qKBJY2Aspgo,779
|
|
28
|
-
ezmsg/sigproc/math/difference.py,sha256=tacbt3KKQOhoYaFMlrASC2GhYQG1J6Hdaa9J1zg_Aw8,1735
|
|
29
|
-
ezmsg/sigproc/math/invert.py,sha256=X6Pp0oYg5A3tpDxfI513xjYg2yXjsosR048AxCWzIwI,667
|
|
30
|
-
ezmsg/sigproc/math/log.py,sha256=T3DST5gpva3lTHmbJkDWVpJyqEVeydUuZSOQCThbvIg,757
|
|
31
|
-
ezmsg/sigproc/math/scale.py,sha256=Ge99e43m1tYoxwQEZ2y-jPq6XQn_IvuKLPaTT2y5vPI,746
|
|
32
|
-
ezmsg_sigproc-1.3.2.dist-info/METADATA,sha256=zFIJ6FXjyBXOcJLjgGE0OO8R_IPKnAIWT8AEQ9SS_io,2376
|
|
33
|
-
ezmsg_sigproc-1.3.2.dist-info/WHEEL,sha256=1yFddiXMmvYK7QYTqtRNtX66WJ0Mz8PYEiEUoOUUxRY,87
|
|
34
|
-
ezmsg_sigproc-1.3.2.dist-info/licenses/LICENSE.txt,sha256=seu0tKhhAMPCUgc1XpXGGaCxY1YaYvFJwqFuQZAl2go,1100
|
|
35
|
-
ezmsg_sigproc-1.3.2.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|