ezmsg-sigproc 1.4.2__py3-none-any.whl → 1.6.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/synth.py CHANGED
@@ -1,18 +1,19 @@
1
1
  import asyncio
2
- from dataclasses import replace, field
2
+ from dataclasses import field
3
3
  import time
4
- from typing import Optional, Generator, AsyncGenerator, Union
4
+ import typing
5
5
 
6
6
  import numpy as np
7
7
  import ezmsg.core as ez
8
8
  from ezmsg.util.generator import consumer
9
9
  from ezmsg.util.messages.axisarray import AxisArray
10
+ from ezmsg.util.messages.util import replace
10
11
 
11
12
  from .butterworthfilter import ButterworthFilter, ButterworthFilterSettings
12
13
  from .base import GenAxisArray
13
14
 
14
15
 
15
- def clock(dispatch_rate: Optional[float]) -> Generator[ez.Flag, None, None]:
16
+ def clock(dispatch_rate: float | None) -> typing.Generator[ez.Flag, None, None]:
16
17
  """
17
18
  Construct a generator that yields events at a specified rate.
18
19
 
@@ -32,7 +33,7 @@ def clock(dispatch_rate: Optional[float]) -> Generator[ez.Flag, None, None]:
32
33
  yield ez.Flag()
33
34
 
34
35
 
35
- async def aclock(dispatch_rate: Optional[float]) -> AsyncGenerator[ez.Flag, None]:
36
+ async def aclock(dispatch_rate: float | None) -> typing.AsyncGenerator[ez.Flag, None]:
36
37
  """
37
38
  ``asyncio`` version of :obj:`clock`.
38
39
 
@@ -53,12 +54,12 @@ class ClockSettings(ez.Settings):
53
54
  """Settings for :obj:`Clock`. See :obj:`clock` for parameter description."""
54
55
 
55
56
  # Message dispatch rate (Hz), or None (fast as possible)
56
- dispatch_rate: Optional[float]
57
+ dispatch_rate: float | None
57
58
 
58
59
 
59
60
  class ClockState(ez.State):
60
61
  cur_settings: ClockSettings
61
- gen: AsyncGenerator
62
+ gen: typing.AsyncGenerator
62
63
 
63
64
 
64
65
  class Clock(ez.Unit):
@@ -83,7 +84,7 @@ class Clock(ez.Unit):
83
84
  self.construct_generator()
84
85
 
85
86
  @ez.publisher(OUTPUT_CLOCK)
86
- async def generate(self) -> AsyncGenerator:
87
+ async def generate(self) -> typing.AsyncGenerator:
87
88
  while True:
88
89
  out = await self.STATE.gen.__anext__()
89
90
  if out:
@@ -93,11 +94,11 @@ class Clock(ez.Unit):
93
94
  # COUNTER - Generate incrementing integer. fs and dispatch_rate parameters combine to give many options. #
94
95
  async def acounter(
95
96
  n_time: int,
96
- fs: Optional[float],
97
+ fs: float | None,
97
98
  n_ch: int = 1,
98
- dispatch_rate: Optional[Union[float, str]] = None,
99
- mod: Optional[int] = None,
100
- ) -> AsyncGenerator[AxisArray, None]:
99
+ dispatch_rate: float | str | None = None,
100
+ mod: int | None = None,
101
+ ) -> typing.AsyncGenerator[AxisArray, None]:
101
102
  """
102
103
  Construct an asynchronous generator to generate AxisArray objects at a specified rate
103
104
  and with the specified sampling rate.
@@ -138,6 +139,17 @@ async def acounter(
138
139
 
139
140
  n_sent: int = 0 # It is convenient to know how many samples we have sent.
140
141
  clock_zero: float = time.time() # time associated with first sample
142
+ template = AxisArray(
143
+ data=np.array([[]]),
144
+ dims=["time", "ch"],
145
+ axes={
146
+ "time": AxisArray.TimeAxis(fs=fs),
147
+ "ch": AxisArray.CoordinateAxis(
148
+ data=np.array([f"Ch{_}" for _ in range(n_ch)]), dims=["ch"]
149
+ ),
150
+ },
151
+ key="acounter",
152
+ )
141
153
 
142
154
  while True:
143
155
  # 1. Sleep, if necessary, until we are at the end of the current block
@@ -167,10 +179,13 @@ async def acounter(
167
179
  # offset += clock_zero # ??
168
180
 
169
181
  # 4. yield output
170
- yield AxisArray(
171
- block_samp,
172
- dims=["time", "ch"],
173
- axes={"time": AxisArray.Axis.TimeAxis(fs=fs, offset=offset)},
182
+ yield replace(
183
+ template,
184
+ data=block_samp,
185
+ axes={
186
+ "time": replace(template.axes["time"], offset=offset),
187
+ "ch": template.axes["ch"],
188
+ },
174
189
  )
175
190
 
176
191
  # 5. Update state for next iteration (after next yield)
@@ -192,14 +207,14 @@ class CounterSettings(ez.Settings):
192
207
  # Message dispatch rate (Hz), 'realtime', 'ext_clock', or None (fast as possible)
193
208
  # Note: if dispatch_rate is a float then time offsets will be synthetic and the
194
209
  # system will run faster or slower than wall clock time.
195
- dispatch_rate: Optional[Union[float, str]] = None
210
+ dispatch_rate: float | str | None = None
196
211
 
197
212
  # If set to an integer, counter will rollover
198
- mod: Optional[int] = None
213
+ mod: int | None = None
199
214
 
200
215
 
201
216
  class CounterState(ez.State):
202
- gen: AsyncGenerator[AxisArray, Optional[ez.Flag]]
217
+ gen: typing.AsyncGenerator[AxisArray, ez.Flag | None]
203
218
  cur_settings: CounterSettings
204
219
  new_generator: asyncio.Event
205
220
 
@@ -248,7 +263,7 @@ class Counter(ez.Unit):
248
263
  yield self.OUTPUT_SIGNAL, out
249
264
 
250
265
  @ez.publisher(OUTPUT_SIGNAL)
251
- async def run_generator(self) -> AsyncGenerator:
266
+ async def run_generator(self) -> typing.AsyncGenerator:
252
267
  while True:
253
268
  await self.STATE.new_generator.wait()
254
269
  self.STATE.new_generator.clear()
@@ -263,16 +278,17 @@ class Counter(ez.Unit):
263
278
 
264
279
  @consumer
265
280
  def sin(
266
- axis: Optional[str] = "time",
281
+ axis: str | None = "time",
267
282
  freq: float = 1.0,
268
283
  amp: float = 1.0,
269
284
  phase: float = 0.0,
270
- ) -> Generator[AxisArray, AxisArray, None]:
285
+ ) -> typing.Generator[AxisArray, AxisArray, None]:
271
286
  """
272
287
  Construct a generator of sinusoidal waveforms in AxisArray objects.
273
288
 
274
289
  Args:
275
290
  axis: The name of the axis over which the sinusoid passes.
291
+ Note: The axis must exist in the msg.axes and be of type AxisArray.LinearAxis.
276
292
  freq: The frequency of the sinusoid, in Hz.
277
293
  amp: The amplitude of the sinusoid.
278
294
  phase: The initial phase of the sinusoid, in radians.
@@ -304,7 +320,7 @@ class SinGeneratorSettings(ez.Settings):
304
320
  See :obj:`sin` for parameter descriptions.
305
321
  """
306
322
 
307
- time_axis: Optional[str] = "time"
323
+ time_axis: str | None = "time"
308
324
  freq: float = 1.0 # Oscillation frequency in Hz
309
325
  amp: float = 1.0 # Amplitude
310
326
  phase: float = 0.0 # Phase offset (in radians)
@@ -338,7 +354,7 @@ class OscillatorSettings(ez.Settings):
338
354
  n_ch: int = 1
339
355
  """Number of channels to output per block"""
340
356
 
341
- dispatch_rate: Optional[Union[float, str]] = None
357
+ dispatch_rate: float | str | None = None
342
358
  """(Hz) | 'realtime' | 'ext_clock'"""
343
359
 
344
360
  freq: float = 1.0
@@ -420,7 +436,7 @@ class RandomGenerator(ez.Unit):
420
436
 
421
437
  @ez.subscriber(INPUT_SIGNAL)
422
438
  @ez.publisher(OUTPUT_SIGNAL)
423
- async def generate(self, msg: AxisArray) -> AsyncGenerator:
439
+ async def generate(self, msg: AxisArray) -> typing.AsyncGenerator:
424
440
  random_data = np.random.normal(
425
441
  size=msg.shape, loc=self.SETTINGS.loc, scale=self.SETTINGS.scale
426
442
  )
@@ -436,7 +452,7 @@ class NoiseSettings(ez.Settings):
436
452
  n_time: int # Number of samples to output per block
437
453
  fs: float # Sampling rate of signal output in Hz
438
454
  n_ch: int = 1 # Number of channels to output
439
- dispatch_rate: Optional[Union[float, str]] = None
455
+ dispatch_rate: float | str | None = None
440
456
  """(Hz), 'realtime', or 'ext_clock'"""
441
457
  loc: float = 0.0 # DC offset
442
458
  scale: float = 1.0 # Scale (in standard deviations)
@@ -538,12 +554,12 @@ class Add(ez.Unit):
538
554
  self.STATE.queue_b.put_nowait(msg)
539
555
 
540
556
  @ez.publisher(OUTPUT_SIGNAL)
541
- async def output(self) -> AsyncGenerator:
557
+ async def output(self) -> typing.AsyncGenerator:
542
558
  while True:
543
559
  a = await self.STATE.queue_a.get()
544
560
  b = await self.STATE.queue_b.get()
545
561
 
546
- yield (self.OUTPUT_SIGNAL, replace(a, data=a.data + b.data))
562
+ yield self.OUTPUT_SIGNAL, replace(a, data=a.data + b.data)
547
563
 
548
564
 
549
565
  class EEGSynthSettings(ez.Settings):
ezmsg/sigproc/wavelets.py CHANGED
@@ -1,4 +1,3 @@
1
- from dataclasses import replace
2
1
  import typing
3
2
 
4
3
  import numpy as np
@@ -6,6 +5,7 @@ import numpy.typing as npt
6
5
  import pywt
7
6
  import ezmsg.core as ez
8
7
  from ezmsg.util.messages.axisarray import AxisArray
8
+ from ezmsg.util.messages.util import replace
9
9
  from ezmsg.util.generator import consumer
10
10
 
11
11
  from .base import GenAxisArray
@@ -14,43 +14,61 @@ from .filterbank import filterbank, FilterbankMode, MinPhaseMode
14
14
 
15
15
  @consumer
16
16
  def cwt(
17
- scales: typing.Union[list, tuple, npt.NDArray],
18
- wavelet: typing.Union[str, pywt.ContinuousWavelet, pywt.Wavelet],
17
+ frequencies: list | tuple | npt.NDArray | None,
18
+ wavelet: str | pywt.ContinuousWavelet | pywt.Wavelet,
19
19
  min_phase: MinPhaseMode = MinPhaseMode.NONE,
20
20
  axis: str = "time",
21
+ scales: list | tuple | npt.NDArray | None = None,
21
22
  ) -> typing.Generator[AxisArray, AxisArray, None]:
22
23
  """
23
24
  Perform a continuous wavelet transform.
24
25
  The function is equivalent to the :obj:`pywt.cwt` function, but is designed to work with streaming data.
25
26
 
26
27
  Args:
27
- scales: The wavelet scales to use.
28
+ frequencies: The wavelet frequencies to use in Hz. If `None` provided then the scales will be used.
29
+ Note: frequencies will be sorted from smallest to largest.
28
30
  wavelet: Wavelet object or name of wavelet to use.
29
31
  min_phase: See filterbank MinPhaseMode for details.
30
32
  axis: The target axis for operation. Note that this will be moved to the -1th dimension
31
33
  because fft and matrix multiplication is much faster on the last axis.
34
+ This axis must be in the msg.axes and it must be of type AxisArray.LinearAxis.
35
+ scales: The scales to use. If None, the scales will be calculated from the frequencies.
36
+ Note: Scales will be sorted from largest to smallest.
37
+ Note: Use of scales is deprecated in favor of frequencies. Convert scales to frequencies using
38
+ `pywt.scale2frequency(wavelet, scales, precision=10) * fs` where fs is the sampling frequency.
32
39
 
33
40
  Returns:
34
41
  A primed Generator object that expects an :obj:`AxisArray` via `.send(axis_array)` of continuous data
35
42
  and yields an :obj:`AxisArray` with a continuous wavelet transform in its data.
36
43
  """
37
- msg_out: typing.Optional[AxisArray] = None
44
+ precision = 10
45
+ msg_out: AxisArray | None = None
38
46
 
39
47
  # Check parameters
40
- scales = np.array(scales)
41
- assert np.all(scales > 0), "Scales must be positive."
42
- assert scales.ndim == 1, "Scales must be a 1D list, tuple, or array."
48
+ if frequencies is None and scales is None:
49
+ raise ValueError("Either frequencies or scales must be provided.")
50
+ if frequencies is not None and scales is not None:
51
+ raise ValueError("Only one of frequencies or scales can be provided.")
52
+ if scales is not None:
53
+ scales = np.sort(scales)[::-1]
54
+ assert np.all(scales > 0), "scales must be positive."
55
+ assert scales.ndim == 1, "scales must be a 1D list, tuple, or array."
56
+
43
57
  if not isinstance(wavelet, (pywt.ContinuousWavelet, pywt.Wavelet)):
44
58
  wavelet = pywt.DiscreteContinuousWavelet(wavelet)
45
- precision = 10
59
+
60
+ if frequencies is not None:
61
+ frequencies = np.sort(frequencies)
62
+ assert np.all(frequencies > 0), "frequencies must be positive."
63
+ assert frequencies.ndim == 1, "frequencies must be a 1D list, tuple, or array."
46
64
 
47
65
  # State variables
48
- neg_rt_scales = -np.sqrt(scales)[:, None]
66
+ neg_rt_scales: npt.NDArray | None = None
49
67
  int_psi, wave_xvec = pywt.integrate_wavelet(wavelet, precision=precision)
50
68
  int_psi = np.conj(int_psi) if wavelet.complex_cwt else int_psi
51
- template: typing.Optional[AxisArray] = None
52
- fbgen: typing.Optional[typing.Generator[AxisArray, AxisArray, None]] = None
53
- last_conv_samp: typing.Optional[npt.NDArray] = None
69
+ template: AxisArray | None = None
70
+ fbgen: typing.Generator[AxisArray, AxisArray, None] | None = None
71
+ last_conv_samp: npt.NDArray | None = None
54
72
 
55
73
  # Reset if input changed
56
74
  check_input = {
@@ -76,6 +94,12 @@ def cwt(
76
94
  check_input["shape"] = in_shape
77
95
  check_input["key"] = msg_in.key
78
96
 
97
+ if frequencies is not None:
98
+ scales = pywt.frequency2scale(
99
+ wavelet, frequencies * msg_in.axes[axis].gain, precision=precision
100
+ )
101
+ neg_rt_scales = -np.sqrt(scales)[:, None]
102
+
79
103
  # convert int_psi, wave_xvec to the same precision as the data
80
104
  dt_data = msg_in.data.dtype # _check_dtype(msg_in.data)
81
105
  dt_cplx = np.result_type(dt_data, np.complex64)
@@ -103,7 +127,6 @@ def cwt(
103
127
  pywt.scale2frequency(wavelet, scales, precision)
104
128
  / msg_in.axes[axis].gain
105
129
  )
106
- fstep = (freqs[1] - freqs[0]) if len(freqs) > 1 else 1.0
107
130
  # Create output template
108
131
  dummy_shape = in_shape + (len(scales), 0)
109
132
  template = AxisArray(
@@ -113,7 +136,9 @@ def cwt(
113
136
  dims=msg_in.dims[:ax_idx] + msg_in.dims[ax_idx + 1 :] + ["freq", axis],
114
137
  axes={
115
138
  **msg_in.axes,
116
- "freq": AxisArray.Axis("Hz", offset=freqs[0], gain=fstep),
139
+ "freq": AxisArray.CoordinateAxis(
140
+ unit="Hz", data=freqs, dims=["freq"]
141
+ ),
117
142
  },
118
143
  key=msg_in.key,
119
144
  )
@@ -147,8 +172,8 @@ class CWTSettings(ez.Settings):
147
172
  See :obj:`cwt` for argument details.
148
173
  """
149
174
 
150
- scales: typing.Union[list, tuple, npt.NDArray]
151
- wavelet: typing.Union[str, pywt.ContinuousWavelet, pywt.Wavelet]
175
+ scales: list | tuple | npt.NDArray
176
+ wavelet: str | pywt.ContinuousWavelet | pywt.Wavelet
152
177
  min_phase: MinPhaseMode = MinPhaseMode.NONE
153
178
  axis: str = "time"
154
179
 
ezmsg/sigproc/window.py CHANGED
@@ -1,4 +1,3 @@
1
- from dataclasses import replace
2
1
  import traceback
3
2
  import typing
4
3
 
@@ -9,6 +8,7 @@ from ezmsg.util.messages.axisarray import (
9
8
  AxisArray,
10
9
  slice_along_axis,
11
10
  sliding_win_oneaxis,
11
+ replace,
12
12
  )
13
13
  from ezmsg.util.generator import consumer
14
14
 
@@ -17,10 +17,10 @@ from .base import GenAxisArray
17
17
 
18
18
  @consumer
19
19
  def windowing(
20
- axis: typing.Optional[str] = None,
20
+ axis: str | None = None,
21
21
  newaxis: str = "win",
22
- window_dur: typing.Optional[float] = None,
23
- window_shift: typing.Optional[float] = None,
22
+ window_dur: float | None = None,
23
+ window_shift: float | None = None,
24
24
  zero_pad_until: str = "input",
25
25
  ) -> typing.Generator[AxisArray, AxisArray, None]:
26
26
  """
@@ -31,6 +31,7 @@ def windowing(
31
31
  Args:
32
32
  axis: The axis along which to segment windows.
33
33
  If None, defaults to the first dimension of the first seen AxisArray.
34
+ Note: The windowed axis must be an AxisArray.LinearAxis, not an AxisArray.CoordinateAxis.
34
35
  newaxis: New axis on which windows are delimited, immediately
35
36
  preceding the target windowed axis. The data length along newaxis may be 0 if
36
37
  this most recent push did not provide enough data for a new window.
@@ -71,15 +72,15 @@ def windowing(
71
72
  msg_out = AxisArray(np.array([]), dims=[""])
72
73
 
73
74
  # State variables
74
- buffer: typing.Optional[npt.NDArray] = None
75
- window_samples: typing.Optional[int] = None
76
- window_shift_samples: typing.Optional[int] = None
75
+ buffer: npt.NDArray | None = None
76
+ window_samples: int | None = None
77
+ window_shift_samples: int | None = None
77
78
  # Number of incoming samples to ignore. Only relevant when shift > window.:
78
79
  shift_deficit: int = 0
79
80
  b_1to1 = window_shift is None
80
81
  newaxis_warned: bool = b_1to1
81
- out_newaxis: typing.Optional[AxisArray.Axis] = None
82
- out_dims: typing.Optional[typing.List[str]] = None
82
+ out_newaxis: AxisArray.LinearAxis | None = None
83
+ out_dims: list[str] | None = None
83
84
 
84
85
  check_inputs = {"samp_shape": None, "fs": None, "key": None}
85
86
 
@@ -215,10 +216,10 @@ def windowing(
215
216
 
216
217
 
217
218
  class WindowSettings(ez.Settings):
218
- axis: typing.Optional[str] = None
219
- newaxis: typing.Optional[str] = None # new axis for output. No new axes if None
220
- window_dur: typing.Optional[float] = None # Sec. passthrough if None
221
- window_shift: typing.Optional[float] = None # Sec. Use "1:1 mode" if None
219
+ axis: str | None = None
220
+ newaxis: str | None = None # new axis for output. No new axes if None
221
+ window_dur: float | None = None # Sec. passthrough if None
222
+ window_shift: float | None = None # Sec. Use "1:1 mode" if None
222
223
  zero_pad_until: str = "full" # "full", "shift", "input", "none"
223
224
 
224
225
 
@@ -1,12 +1,11 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: ezmsg-sigproc
3
- Version: 1.4.2
3
+ Version: 1.6.0
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
- License-Expression: MIT
7
- License-File: LICENSE.txt
8
- Requires-Python: >=3.9
9
- Requires-Dist: ezmsg>=3.5.0
6
+ License: MIT
7
+ Requires-Python: >=3.10.15
8
+ Requires-Dist: ezmsg>=3.6.0
10
9
  Requires-Dist: numpy>=1.26.0
11
10
  Requires-Dist: pywavelets>=1.6.0
12
11
  Requires-Dist: scipy>=1.13.1
@@ -0,0 +1,36 @@
1
+ ezmsg/sigproc/__init__.py,sha256=8K4IcOA3-pfzadoM6s2Sfg5460KlJUocGgyTJTJl96U,52
2
+ ezmsg/sigproc/__version__.py,sha256=Ry70pc5l-IBhT9gahlkNwZPp4g0CzVEWqsat9H-UASY,411
3
+ ezmsg/sigproc/activation.py,sha256=LM-MtaNvFvmBZ1_EPNu--4K3-wIzsb7CUQ00fvMM69g,2642
4
+ ezmsg/sigproc/affinetransform.py,sha256=R2P1f5JdNSpr30x8Pxoqv-J-nAasGl_UZR8o7sVqlaQ,8740
5
+ ezmsg/sigproc/aggregate.py,sha256=6BqAujWe7_zzGPDJz7yh4ofPzJTU5z2lrclX-IuqXDU,6235
6
+ ezmsg/sigproc/bandpower.py,sha256=Mx8iUU-UMWKK5sgCXvxpUSA3522rW8Jg96asrT8MdpA,2180
7
+ ezmsg/sigproc/base.py,sha256=vut0BLjgc0mxYRbs7tDd9XzwRFA2_GcsgXZmIYovR0Y,1248
8
+ ezmsg/sigproc/butterworthfilter.py,sha256=vZTY37FfLwa24bRZmeZGyO5323824wJosUrrZarb0_o,5402
9
+ ezmsg/sigproc/cheby.py,sha256=yds5y1fOeBE1ljyH_EreBLxqFX4UetxB_3rwz3omHyc,3394
10
+ ezmsg/sigproc/decimate.py,sha256=Cu2weOIKGoo_pUSpA90N47kuzcT6s7OAa1HaF7u3cY0,1286
11
+ ezmsg/sigproc/downsample.py,sha256=oJ0VOZ0UrLAhce2bolSom23LD8Ob-8LCOmzqkrZCJ0E,3454
12
+ ezmsg/sigproc/ewmfilter.py,sha256=EPlocRdKORj575VV1YUzcNsVcq-pYgdEJ7_m9WfpVnY,4795
13
+ ezmsg/sigproc/filter.py,sha256=n3_gColSPXe4pI-A2VDKfrdFHZgC-k4kqB8H6tnGIws,6969
14
+ ezmsg/sigproc/filterbank.py,sha256=pySLNGppnG6Dx9r5jQpNSyWhd9qmvj6up2udG7RMNok,12410
15
+ ezmsg/sigproc/messages.py,sha256=y_twVPK7TxRj8ajmuSuBuxwvLTgyv9OF7Y7v9bw1tfs,926
16
+ ezmsg/sigproc/sampler.py,sha256=ljZuToiC5p4Jx2cJPXJ4tOtv3nBOBGMEaz7ad7Nec8U,12735
17
+ ezmsg/sigproc/scaler.py,sha256=5uCgVbZHV9iCsAVnc9Pz7hKIXnaIiA9ssiTCce_QHlU,9550
18
+ ezmsg/sigproc/signalinjector.py,sha256=-_cln7Ljny0WWrjBV3HZhhONLEkEphsgLS30AWlxcOE,2590
19
+ ezmsg/sigproc/slicer.py,sha256=n6JGOkkY2ur5K1STsLQDSvFhEjT2ZLiSxmggK6qEmpc,5731
20
+ ezmsg/sigproc/spectral.py,sha256=_2qO6as4Nesmc9V1WW2EXNMH5pPz8aVTEcIPOi4-g2o,322
21
+ ezmsg/sigproc/spectrogram.py,sha256=Xc3zXKjVwG0-NLzKEsVKv253Sk50t2U1SlqEJ_ll36k,3086
22
+ ezmsg/sigproc/spectrum.py,sha256=ZhsWlxUiTaWc8qgNZ5NWqsU_fNmjb4V5532mNA8Bd5Y,9396
23
+ ezmsg/sigproc/synth.py,sha256=kobTQwAyiNZLbpJIUNxI6SOiuKm0aca2G5pSjuB4K9E,18823
24
+ ezmsg/sigproc/wavelets.py,sha256=bwlqyUESrOWAiI_gECbaKJj0PflnFMmuYtNridBTfNs,7955
25
+ ezmsg/sigproc/window.py,sha256=eIxdtni6BwDmpko6m_WJnUDO3VHb5y7jM6nU9WyzIsM,13056
26
+ ezmsg/sigproc/math/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
27
+ ezmsg/sigproc/math/abs.py,sha256=Hjnn2x8djWLUDVqvxRC4V7jOvgEtdU6CCHGpfVZ0uOY,931
28
+ ezmsg/sigproc/math/clip.py,sha256=UpFLP_IkrY6bo4WcIpO4Czbttg7n6hybAihOGy-3nGs,1144
29
+ ezmsg/sigproc/math/difference.py,sha256=I96Md2pyfCU5TSw35u1uS6FaPJRv0JpHQVhrTHv1BQ0,2196
30
+ ezmsg/sigproc/math/invert.py,sha256=T6PEhBCquKRJQF6LfUgqjXKSBsS_tvi4BJAqJ_5VCjw,895
31
+ ezmsg/sigproc/math/log.py,sha256=i-iF2WDH18RWapYwlhAsiDdhzvuJY9mDWrNtjfuiyL8,1572
32
+ ezmsg/sigproc/math/scale.py,sha256=lQKF02Mv9nTWfgc4OcMpQMCx993p57GSN-AADeO2fjY,1063
33
+ ezmsg_sigproc-1.6.0.dist-info/METADATA,sha256=-Y0s91NhAEO_KWsBo1KQKPQE4IDyU-xp51rOa8FuUAo,2343
34
+ ezmsg_sigproc-1.6.0.dist-info/WHEEL,sha256=C2FUgwZgiLbznR-k0b_5k3Ai_1aASOXDss3lzCUsUug,87
35
+ ezmsg_sigproc-1.6.0.dist-info/licenses/LICENSE.txt,sha256=seu0tKhhAMPCUgc1XpXGGaCxY1YaYvFJwqFuQZAl2go,1100
36
+ ezmsg_sigproc-1.6.0.dist-info/RECORD,,
@@ -1,4 +1,4 @@
1
1
  Wheel-Version: 1.0
2
- Generator: hatchling 1.25.0
2
+ Generator: hatchling 1.26.3
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
@@ -1,35 +0,0 @@
1
- ezmsg/sigproc/__init__.py,sha256=8K4IcOA3-pfzadoM6s2Sfg5460KlJUocGgyTJTJl96U,52
2
- ezmsg/sigproc/__version__.py,sha256=tX44urJsC0QN5SJ51xsM0HeojA_8Xx7NXFEGAkYlNE4,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=oot0tT0wVvdI0UlPOqj1tQLDn_gIxf8em_b4NfJRmW0,1559
31
- ezmsg/sigproc/math/scale.py,sha256=iIQuJAr5pzCiMqzi2YdzLc1agQBKBOcngdNZlLO3X_o,1050
32
- ezmsg_sigproc-1.4.2.dist-info/METADATA,sha256=islU0_cvDjX0iqp202X5_eD-Qu37_9wKsBOo_cKcV8c,2376
33
- ezmsg_sigproc-1.4.2.dist-info/WHEEL,sha256=1yFddiXMmvYK7QYTqtRNtX66WJ0Mz8PYEiEUoOUUxRY,87
34
- ezmsg_sigproc-1.4.2.dist-info/licenses/LICENSE.txt,sha256=seu0tKhhAMPCUgc1XpXGGaCxY1YaYvFJwqFuQZAl2go,1100
35
- ezmsg_sigproc-1.4.2.dist-info/RECORD,,