ezmsg-sigproc 2.5.0__tar.gz → 2.6.0__tar.gz

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 (173) hide show
  1. {ezmsg_sigproc-2.5.0 → ezmsg_sigproc-2.6.0}/.github/workflows/docs.yml +5 -4
  2. ezmsg_sigproc-2.6.0/.github/workflows/python-publish.yml +29 -0
  3. {ezmsg_sigproc-2.5.0 → ezmsg_sigproc-2.6.0}/.pre-commit-config.yaml +1 -2
  4. {ezmsg_sigproc-2.5.0 → ezmsg_sigproc-2.6.0}/PKG-INFO +3 -2
  5. {ezmsg_sigproc-2.5.0 → ezmsg_sigproc-2.6.0}/docs/source/conf.py +1 -0
  6. ezmsg_sigproc-2.6.0/docs/source/guides/ProcessorsBase.md +58 -0
  7. ezmsg_sigproc-2.6.0/docs/source/guides/how-tos/signalprocessing/composite.rst +6 -0
  8. ezmsg_sigproc-2.6.0/docs/source/guides/how-tos/signalprocessing/processor.rst +8 -0
  9. ezmsg_sigproc-2.6.0/docs/source/guides/how-tos/signalprocessing/stateful.rst +8 -0
  10. ezmsg_sigproc-2.6.0/docs/source/guides/how-tos/signalprocessing/unit.rst +41 -0
  11. ezmsg_sigproc-2.6.0/docs/source/guides/sigproc/base.rst +19 -0
  12. {ezmsg_sigproc-2.5.0 → ezmsg_sigproc-2.6.0}/pyproject.toml +20 -0
  13. {ezmsg_sigproc-2.5.0 → ezmsg_sigproc-2.6.0}/src/ezmsg/sigproc/__version__.py +2 -2
  14. {ezmsg_sigproc-2.5.0 → ezmsg_sigproc-2.6.0}/src/ezmsg/sigproc/activation.py +5 -11
  15. {ezmsg_sigproc-2.5.0 → ezmsg_sigproc-2.6.0}/src/ezmsg/sigproc/adaptive_lattice_notch.py +11 -29
  16. {ezmsg_sigproc-2.5.0 → ezmsg_sigproc-2.6.0}/src/ezmsg/sigproc/affinetransform.py +13 -38
  17. {ezmsg_sigproc-2.5.0 → ezmsg_sigproc-2.6.0}/src/ezmsg/sigproc/aggregate.py +13 -30
  18. {ezmsg_sigproc-2.5.0 → ezmsg_sigproc-2.6.0}/src/ezmsg/sigproc/bandpower.py +7 -15
  19. ezmsg_sigproc-2.6.0/src/ezmsg/sigproc/base.py +149 -0
  20. {ezmsg_sigproc-2.5.0 → ezmsg_sigproc-2.6.0}/src/ezmsg/sigproc/butterworthfilter.py +8 -16
  21. {ezmsg_sigproc-2.5.0 → ezmsg_sigproc-2.6.0}/src/ezmsg/sigproc/butterworthzerophase.py +7 -16
  22. {ezmsg_sigproc-2.5.0 → ezmsg_sigproc-2.6.0}/src/ezmsg/sigproc/cheby.py +4 -10
  23. {ezmsg_sigproc-2.5.0 → ezmsg_sigproc-2.6.0}/src/ezmsg/sigproc/combfilter.py +5 -8
  24. {ezmsg_sigproc-2.5.0 → ezmsg_sigproc-2.6.0}/src/ezmsg/sigproc/decimate.py +2 -6
  25. {ezmsg_sigproc-2.5.0 → ezmsg_sigproc-2.6.0}/src/ezmsg/sigproc/denormalize.py +6 -11
  26. {ezmsg_sigproc-2.5.0 → ezmsg_sigproc-2.6.0}/src/ezmsg/sigproc/detrend.py +3 -4
  27. {ezmsg_sigproc-2.5.0 → ezmsg_sigproc-2.6.0}/src/ezmsg/sigproc/diff.py +8 -17
  28. {ezmsg_sigproc-2.5.0 → ezmsg_sigproc-2.6.0}/src/ezmsg/sigproc/downsample.py +6 -14
  29. {ezmsg_sigproc-2.5.0 → ezmsg_sigproc-2.6.0}/src/ezmsg/sigproc/ewma.py +11 -27
  30. {ezmsg_sigproc-2.5.0 → ezmsg_sigproc-2.6.0}/src/ezmsg/sigproc/extract_axis.py +3 -4
  31. {ezmsg_sigproc-2.5.0 → ezmsg_sigproc-2.6.0}/src/ezmsg/sigproc/fbcca.py +31 -56
  32. {ezmsg_sigproc-2.5.0 → ezmsg_sigproc-2.6.0}/src/ezmsg/sigproc/filter.py +19 -45
  33. {ezmsg_sigproc-2.5.0 → ezmsg_sigproc-2.6.0}/src/ezmsg/sigproc/filterbank.py +33 -70
  34. {ezmsg_sigproc-2.5.0 → ezmsg_sigproc-2.6.0}/src/ezmsg/sigproc/filterbankdesign.py +5 -12
  35. {ezmsg_sigproc-2.5.0 → ezmsg_sigproc-2.6.0}/src/ezmsg/sigproc/fir_hilbert.py +13 -30
  36. {ezmsg_sigproc-2.5.0 → ezmsg_sigproc-2.6.0}/src/ezmsg/sigproc/fir_pmc.py +5 -10
  37. {ezmsg_sigproc-2.5.0 → ezmsg_sigproc-2.6.0}/src/ezmsg/sigproc/firfilter.py +12 -14
  38. {ezmsg_sigproc-2.5.0 → ezmsg_sigproc-2.6.0}/src/ezmsg/sigproc/gaussiansmoothing.py +5 -9
  39. {ezmsg_sigproc-2.5.0 → ezmsg_sigproc-2.6.0}/src/ezmsg/sigproc/kaiser.py +11 -15
  40. {ezmsg_sigproc-2.5.0 → ezmsg_sigproc-2.6.0}/src/ezmsg/sigproc/math/abs.py +1 -3
  41. ezmsg_sigproc-2.6.0/src/ezmsg/sigproc/math/add.py +121 -0
  42. ezmsg_sigproc-2.6.0/src/ezmsg/sigproc/math/difference.py +135 -0
  43. {ezmsg_sigproc-2.5.0 → ezmsg_sigproc-2.6.0}/src/ezmsg/sigproc/math/invert.py +1 -3
  44. {ezmsg_sigproc-2.5.0 → ezmsg_sigproc-2.6.0}/src/ezmsg/sigproc/math/log.py +2 -6
  45. {ezmsg_sigproc-2.5.0 → ezmsg_sigproc-2.6.0}/src/ezmsg/sigproc/messages.py +1 -2
  46. {ezmsg_sigproc-2.5.0 → ezmsg_sigproc-2.6.0}/src/ezmsg/sigproc/quantize.py +2 -4
  47. {ezmsg_sigproc-2.5.0 → ezmsg_sigproc-2.6.0}/src/ezmsg/sigproc/resample.py +13 -34
  48. {ezmsg_sigproc-2.5.0 → ezmsg_sigproc-2.6.0}/src/ezmsg/sigproc/rollingscaler.py +12 -37
  49. {ezmsg_sigproc-2.5.0 → ezmsg_sigproc-2.6.0}/src/ezmsg/sigproc/sampler.py +17 -35
  50. {ezmsg_sigproc-2.5.0 → ezmsg_sigproc-2.6.0}/src/ezmsg/sigproc/scaler.py +8 -18
  51. {ezmsg_sigproc-2.5.0 → ezmsg_sigproc-2.6.0}/src/ezmsg/sigproc/signalinjector.py +6 -16
  52. {ezmsg_sigproc-2.5.0 → ezmsg_sigproc-2.6.0}/src/ezmsg/sigproc/slicer.py +9 -28
  53. {ezmsg_sigproc-2.5.0 → ezmsg_sigproc-2.6.0}/src/ezmsg/sigproc/spectrogram.py +12 -19
  54. {ezmsg_sigproc-2.5.0 → ezmsg_sigproc-2.6.0}/src/ezmsg/sigproc/spectrum.py +12 -32
  55. {ezmsg_sigproc-2.5.0 → ezmsg_sigproc-2.6.0}/src/ezmsg/sigproc/transpose.py +7 -18
  56. ezmsg_sigproc-2.6.0/src/ezmsg/sigproc/util/asio.py +25 -0
  57. {ezmsg_sigproc-2.5.0 → ezmsg_sigproc-2.6.0}/src/ezmsg/sigproc/util/axisarray_buffer.py +10 -26
  58. {ezmsg_sigproc-2.5.0 → ezmsg_sigproc-2.6.0}/src/ezmsg/sigproc/util/buffer.py +18 -43
  59. ezmsg_sigproc-2.6.0/src/ezmsg/sigproc/util/message.py +17 -0
  60. ezmsg_sigproc-2.6.0/src/ezmsg/sigproc/util/profile.py +23 -0
  61. {ezmsg_sigproc-2.5.0 → ezmsg_sigproc-2.6.0}/src/ezmsg/sigproc/util/sparse.py +5 -15
  62. ezmsg_sigproc-2.6.0/src/ezmsg/sigproc/util/typeresolution.py +17 -0
  63. {ezmsg_sigproc-2.5.0 → ezmsg_sigproc-2.6.0}/src/ezmsg/sigproc/wavelets.py +6 -15
  64. {ezmsg_sigproc-2.5.0 → ezmsg_sigproc-2.6.0}/src/ezmsg/sigproc/window.py +24 -78
  65. ezmsg_sigproc-2.6.0/tests/helpers/synth.py +281 -0
  66. {ezmsg_sigproc-2.5.0 → ezmsg_sigproc-2.6.0}/tests/helpers/util.py +9 -18
  67. {ezmsg_sigproc-2.5.0 → ezmsg_sigproc-2.6.0}/tests/integration/bytewax/test_spectrum_bytewax.py +4 -4
  68. {ezmsg_sigproc-2.5.0 → ezmsg_sigproc-2.6.0}/tests/integration/bytewax/test_window_bytewax.py +3 -3
  69. ezmsg_sigproc-2.6.0/tests/integration/ezmsg/test_add_system.py +148 -0
  70. {ezmsg_sigproc-2.5.0 → ezmsg_sigproc-2.6.0}/tests/integration/ezmsg/test_butterworth_system.py +10 -20
  71. {ezmsg_sigproc-2.5.0 → ezmsg_sigproc-2.6.0}/tests/integration/ezmsg/test_butterworthzerophase_system.py +1 -1
  72. {ezmsg_sigproc-2.5.0 → ezmsg_sigproc-2.6.0}/tests/integration/ezmsg/test_decimate_system.py +5 -8
  73. ezmsg_sigproc-2.6.0/tests/integration/ezmsg/test_difference_system.py +203 -0
  74. {ezmsg_sigproc-2.5.0 → ezmsg_sigproc-2.6.0}/tests/integration/ezmsg/test_downsample_system.py +10 -13
  75. {ezmsg_sigproc-2.5.0 → ezmsg_sigproc-2.6.0}/tests/integration/ezmsg/test_filter_system.py +9 -20
  76. {ezmsg_sigproc-2.5.0 → ezmsg_sigproc-2.6.0}/tests/integration/ezmsg/test_fir_hilbert_system.py +1 -1
  77. {ezmsg_sigproc-2.5.0 → ezmsg_sigproc-2.6.0}/tests/integration/ezmsg/test_fir_pmc_system.py +1 -1
  78. {ezmsg_sigproc-2.5.0 → ezmsg_sigproc-2.6.0}/tests/integration/ezmsg/test_rollingscaler_system.py +1 -1
  79. {ezmsg_sigproc-2.5.0 → ezmsg_sigproc-2.6.0}/tests/integration/ezmsg/test_sampler_system.py +7 -13
  80. {ezmsg_sigproc-2.5.0 → ezmsg_sigproc-2.6.0}/tests/integration/ezmsg/test_scaler_system.py +8 -13
  81. {ezmsg_sigproc-2.5.0 → ezmsg_sigproc-2.6.0}/tests/integration/ezmsg/test_spectrum_system.py +9 -10
  82. {ezmsg_sigproc-2.5.0 → ezmsg_sigproc-2.6.0}/tests/integration/ezmsg/test_window_system.py +10 -17
  83. ezmsg_sigproc-2.6.0/tests/test_profile.py +39 -0
  84. {ezmsg_sigproc-2.5.0 → ezmsg_sigproc-2.6.0}/tests/unit/buffer/test_axisarray_buffer.py +6 -12
  85. {ezmsg_sigproc-2.5.0 → ezmsg_sigproc-2.6.0}/tests/unit/buffer/test_buffer.py +2 -1
  86. {ezmsg_sigproc-2.5.0 → ezmsg_sigproc-2.6.0}/tests/unit/buffer/test_buffer_overflow.py +10 -21
  87. {ezmsg_sigproc-2.5.0 → ezmsg_sigproc-2.6.0}/tests/unit/test_activation.py +4 -9
  88. {ezmsg_sigproc-2.5.0 → ezmsg_sigproc-2.6.0}/tests/unit/test_adaptive_lattice_notch.py +5 -17
  89. {ezmsg_sigproc-2.5.0 → ezmsg_sigproc-2.6.0}/tests/unit/test_affine_transform.py +2 -9
  90. {ezmsg_sigproc-2.5.0 → ezmsg_sigproc-2.6.0}/tests/unit/test_aggregate.py +20 -56
  91. {ezmsg_sigproc-2.5.0 → ezmsg_sigproc-2.6.0}/tests/unit/test_bandpower.py +2 -2
  92. {ezmsg_sigproc-2.5.0 → ezmsg_sigproc-2.6.0}/tests/unit/test_base.py +52 -133
  93. {ezmsg_sigproc-2.5.0 → ezmsg_sigproc-2.6.0}/tests/unit/test_butter.py +8 -20
  94. {ezmsg_sigproc-2.5.0 → ezmsg_sigproc-2.6.0}/tests/unit/test_butterworthzerophase.py +7 -21
  95. {ezmsg_sigproc-2.5.0 → ezmsg_sigproc-2.6.0}/tests/unit/test_combfilter.py +9 -24
  96. {ezmsg_sigproc-2.5.0 → ezmsg_sigproc-2.6.0}/tests/unit/test_denormalize.py +7 -20
  97. {ezmsg_sigproc-2.5.0 → ezmsg_sigproc-2.6.0}/tests/unit/test_diff.py +3 -3
  98. {ezmsg_sigproc-2.5.0 → ezmsg_sigproc-2.6.0}/tests/unit/test_downsample.py +5 -12
  99. {ezmsg_sigproc-2.5.0 → ezmsg_sigproc-2.6.0}/tests/unit/test_ewma.py +4 -8
  100. {ezmsg_sigproc-2.5.0 → ezmsg_sigproc-2.6.0}/tests/unit/test_extract_axis.py +3 -5
  101. {ezmsg_sigproc-2.5.0 → ezmsg_sigproc-2.6.0}/tests/unit/test_fbcca.py +27 -85
  102. {ezmsg_sigproc-2.5.0 → ezmsg_sigproc-2.6.0}/tests/unit/test_filter.py +2 -1
  103. {ezmsg_sigproc-2.5.0 → ezmsg_sigproc-2.6.0}/tests/unit/test_filterbank.py +5 -12
  104. {ezmsg_sigproc-2.5.0 → ezmsg_sigproc-2.6.0}/tests/unit/test_filterbankdesign.py +22 -63
  105. {ezmsg_sigproc-2.5.0 → ezmsg_sigproc-2.6.0}/tests/unit/test_fir_hilbert.py +4 -12
  106. {ezmsg_sigproc-2.5.0 → ezmsg_sigproc-2.6.0}/tests/unit/test_firfilter.py +2 -4
  107. {ezmsg_sigproc-2.5.0 → ezmsg_sigproc-2.6.0}/tests/unit/test_gaussian_smoothing_filter.py +6 -14
  108. {ezmsg_sigproc-2.5.0 → ezmsg_sigproc-2.6.0}/tests/unit/test_kaiser.py +4 -10
  109. {ezmsg_sigproc-2.5.0 → ezmsg_sigproc-2.6.0}/tests/unit/test_math.py +1 -4
  110. ezmsg_sigproc-2.6.0/tests/unit/test_math_add.py +247 -0
  111. ezmsg_sigproc-2.6.0/tests/unit/test_math_difference.py +278 -0
  112. {ezmsg_sigproc-2.5.0 → ezmsg_sigproc-2.6.0}/tests/unit/test_quantize.py +4 -9
  113. {ezmsg_sigproc-2.5.0 → ezmsg_sigproc-2.6.0}/tests/unit/test_resample.py +8 -22
  114. {ezmsg_sigproc-2.5.0 → ezmsg_sigproc-2.6.0}/tests/unit/test_rollingscaler.py +5 -13
  115. {ezmsg_sigproc-2.5.0 → ezmsg_sigproc-2.6.0}/tests/unit/test_sampler.py +9 -25
  116. {ezmsg_sigproc-2.5.0 → ezmsg_sigproc-2.6.0}/tests/unit/test_scaler.py +4 -7
  117. {ezmsg_sigproc-2.5.0 → ezmsg_sigproc-2.6.0}/tests/unit/test_slicer.py +5 -12
  118. {ezmsg_sigproc-2.5.0 → ezmsg_sigproc-2.6.0}/tests/unit/test_spectrogram.py +6 -13
  119. {ezmsg_sigproc-2.5.0 → ezmsg_sigproc-2.6.0}/tests/unit/test_spectrum.py +14 -29
  120. {ezmsg_sigproc-2.5.0 → ezmsg_sigproc-2.6.0}/tests/unit/test_transpose.py +2 -5
  121. {ezmsg_sigproc-2.5.0 → ezmsg_sigproc-2.6.0}/tests/unit/test_util.py +17 -51
  122. {ezmsg_sigproc-2.5.0 → ezmsg_sigproc-2.6.0}/tests/unit/test_wavelets.py +4 -9
  123. {ezmsg_sigproc-2.5.0 → ezmsg_sigproc-2.6.0}/tests/unit/test_window.py +11 -30
  124. ezmsg_sigproc-2.5.0/.github/workflows/python-publish-ezmsg-sigproc.yml +0 -30
  125. ezmsg_sigproc-2.5.0/docs/source/guides/ProcessorsBase.md +0 -173
  126. ezmsg_sigproc-2.5.0/docs/source/guides/how-tos/signalprocessing/composite.rst +0 -4
  127. ezmsg_sigproc-2.5.0/docs/source/guides/how-tos/signalprocessing/processor.rst +0 -4
  128. ezmsg_sigproc-2.5.0/docs/source/guides/how-tos/signalprocessing/stateful.rst +0 -4
  129. ezmsg_sigproc-2.5.0/docs/source/guides/how-tos/signalprocessing/unit.rst +0 -11
  130. ezmsg_sigproc-2.5.0/docs/source/guides/sigproc/base.rst +0 -65
  131. ezmsg_sigproc-2.5.0/src/ezmsg/sigproc/base.py +0 -1284
  132. ezmsg_sigproc-2.5.0/src/ezmsg/sigproc/math/difference.py +0 -73
  133. ezmsg_sigproc-2.5.0/src/ezmsg/sigproc/synth.py +0 -774
  134. ezmsg_sigproc-2.5.0/src/ezmsg/sigproc/util/asio.py +0 -156
  135. ezmsg_sigproc-2.5.0/src/ezmsg/sigproc/util/message.py +0 -31
  136. ezmsg_sigproc-2.5.0/src/ezmsg/sigproc/util/profile.py +0 -174
  137. ezmsg_sigproc-2.5.0/src/ezmsg/sigproc/util/typeresolution.py +0 -83
  138. ezmsg_sigproc-2.5.0/tests/integration/ezmsg/test_synth_system.py +0 -243
  139. ezmsg_sigproc-2.5.0/tests/test_profile.py +0 -191
  140. ezmsg_sigproc-2.5.0/tests/unit/test_synth.py +0 -150
  141. {ezmsg_sigproc-2.5.0 → ezmsg_sigproc-2.6.0}/.github/workflows/python-tests.yml +0 -0
  142. {ezmsg_sigproc-2.5.0 → ezmsg_sigproc-2.6.0}/.gitignore +0 -0
  143. ezmsg_sigproc-2.5.0/LICENSE.txt → ezmsg_sigproc-2.6.0/LICENSE +0 -0
  144. {ezmsg_sigproc-2.5.0 → ezmsg_sigproc-2.6.0}/README.md +0 -0
  145. {ezmsg_sigproc-2.5.0 → ezmsg_sigproc-2.6.0}/docs/Makefile +0 -0
  146. {ezmsg_sigproc-2.5.0 → ezmsg_sigproc-2.6.0}/docs/make.bat +0 -0
  147. {ezmsg_sigproc-2.5.0 → ezmsg_sigproc-2.6.0}/docs/source/_templates/autosummary/module.rst +0 -0
  148. {ezmsg_sigproc-2.5.0 → ezmsg_sigproc-2.6.0}/docs/source/api/index.rst +0 -0
  149. {ezmsg_sigproc-2.5.0 → ezmsg_sigproc-2.6.0}/docs/source/guides/HybridBuffer.md +0 -0
  150. {ezmsg_sigproc-2.5.0 → ezmsg_sigproc-2.6.0}/docs/source/guides/explanations/sigproc.rst +0 -0
  151. {ezmsg_sigproc-2.5.0 → ezmsg_sigproc-2.6.0}/docs/source/guides/how-tos/signalprocessing/adaptive.rst +0 -0
  152. {ezmsg_sigproc-2.5.0 → ezmsg_sigproc-2.6.0}/docs/source/guides/how-tos/signalprocessing/checkpoint.rst +0 -0
  153. {ezmsg_sigproc-2.5.0 → ezmsg_sigproc-2.6.0}/docs/source/guides/how-tos/signalprocessing/content-signalprocessing.rst +0 -0
  154. {ezmsg_sigproc-2.5.0 → ezmsg_sigproc-2.6.0}/docs/source/guides/how-tos/signalprocessing/standalone.rst +0 -0
  155. {ezmsg_sigproc-2.5.0 → ezmsg_sigproc-2.6.0}/docs/source/guides/img/HybridBufferBasic.svg +0 -0
  156. {ezmsg_sigproc-2.5.0 → ezmsg_sigproc-2.6.0}/docs/source/guides/img/HybridBufferOverflow.svg +0 -0
  157. {ezmsg_sigproc-2.5.0 → ezmsg_sigproc-2.6.0}/docs/source/guides/sigproc/content-sigproc.rst +0 -0
  158. {ezmsg_sigproc-2.5.0 → ezmsg_sigproc-2.6.0}/docs/source/guides/sigproc/processors.rst +0 -0
  159. {ezmsg_sigproc-2.5.0 → ezmsg_sigproc-2.6.0}/docs/source/guides/sigproc/units.rst +0 -0
  160. {ezmsg_sigproc-2.5.0 → ezmsg_sigproc-2.6.0}/docs/source/guides/tutorials/signalprocessing.rst +0 -0
  161. {ezmsg_sigproc-2.5.0 → ezmsg_sigproc-2.6.0}/docs/source/index.rst +0 -0
  162. {ezmsg_sigproc-2.5.0 → ezmsg_sigproc-2.6.0}/src/ezmsg/sigproc/__init__.py +0 -0
  163. {ezmsg_sigproc-2.5.0 → ezmsg_sigproc-2.6.0}/src/ezmsg/sigproc/ewmfilter.py +1 -1
  164. {ezmsg_sigproc-2.5.0 → ezmsg_sigproc-2.6.0}/src/ezmsg/sigproc/math/__init__.py +0 -0
  165. {ezmsg_sigproc-2.5.0 → ezmsg_sigproc-2.6.0}/src/ezmsg/sigproc/math/clip.py +1 -1
  166. {ezmsg_sigproc-2.5.0 → ezmsg_sigproc-2.6.0}/src/ezmsg/sigproc/math/scale.py +0 -0
  167. {ezmsg_sigproc-2.5.0 → ezmsg_sigproc-2.6.0}/src/ezmsg/sigproc/spectral.py +3 -3
  168. {ezmsg_sigproc-2.5.0 → ezmsg_sigproc-2.6.0}/src/ezmsg/sigproc/util/__init__.py +0 -0
  169. {ezmsg_sigproc-2.5.0 → ezmsg_sigproc-2.6.0}/tests/__init__.py +0 -0
  170. {ezmsg_sigproc-2.5.0 → ezmsg_sigproc-2.6.0}/tests/conftest.py +1 -1
  171. {ezmsg_sigproc-2.5.0 → ezmsg_sigproc-2.6.0}/tests/helpers/__init__.py +0 -0
  172. {ezmsg_sigproc-2.5.0 → ezmsg_sigproc-2.6.0}/tests/resources/xform.csv +0 -0
  173. {ezmsg_sigproc-2.5.0 → ezmsg_sigproc-2.6.0}/tests/unit/test_fir_pmc.py +0 -0
@@ -4,11 +4,12 @@ on:
4
4
  push:
5
5
  branches:
6
6
  - main
7
- tags:
8
- - 'v*'
9
7
  pull_request:
10
8
  branches:
9
+ - main
11
10
  - dev
11
+ release:
12
+ types: [published]
12
13
  workflow_dispatch:
13
14
 
14
15
  permissions:
@@ -52,8 +53,8 @@ jobs:
52
53
  path: 'docs/build/html'
53
54
 
54
55
  deploy:
55
- # Only deploy on push to main or release tags
56
- if: github.event_name == 'push' && (github.ref == 'refs/heads/main' || startsWith(github.ref, 'refs/tags/v'))
56
+ # Only deploy when a release is published
57
+ if: github.event_name == 'release'
57
58
  environment:
58
59
  name: github-pages
59
60
  url: ${{ steps.deployment.outputs.page_url }}
@@ -0,0 +1,29 @@
1
+ name: Upload Python Package
2
+
3
+ on:
4
+ release:
5
+ types: [published]
6
+ workflow_dispatch:
7
+
8
+ permissions:
9
+ contents: read
10
+
11
+ jobs:
12
+ build:
13
+ name: build and upload release to PyPI
14
+ runs-on: ubuntu-latest
15
+ environment: "release"
16
+ permissions:
17
+ id-token: write # IMPORTANT: this permission is mandatory for trusted publishing
18
+
19
+ steps:
20
+ - uses: actions/checkout@v4
21
+
22
+ - name: Install uv
23
+ uses: astral-sh/setup-uv@v6
24
+
25
+ - name: Build Package
26
+ run: uv build
27
+
28
+ - name: Publish package distributions to PyPI
29
+ run: uv publish
@@ -1,7 +1,6 @@
1
1
  repos:
2
2
  - repo: https://github.com/astral-sh/ruff-pre-commit
3
- # Ruff version.
4
- rev: v0.6.7
3
+ rev: v0.8.3
5
4
  hooks:
6
5
  # Run the linter.
7
6
  - id: ruff
@@ -1,12 +1,13 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: ezmsg-sigproc
3
- Version: 2.5.0
3
+ Version: 2.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>, Kyle McGraw <kmcgraw@blackrockneuro.com>
6
6
  License-Expression: MIT
7
- License-File: LICENSE.txt
7
+ License-File: LICENSE
8
8
  Requires-Python: >=3.10.15
9
9
  Requires-Dist: array-api-compat>=1.11.1
10
+ Requires-Dist: ezmsg-baseproc>=1.0.3
10
11
  Requires-Dist: ezmsg>=3.6.0
11
12
  Requires-Dist: numba>=0.61.0
12
13
  Requires-Dist: numpy>=1.26.0
@@ -72,6 +72,7 @@ intersphinx_mapping = {
72
72
  "numpy": ("https://numpy.org/doc/stable/", None),
73
73
  "scipy": ("https://scipy.org/doc/scipy/", None),
74
74
  "ezmsg": ("https://www.ezmsg.org/ezmsg/", None),
75
+ "ezmsg.baseproc": ("https://www.ezmsg.org/ezmsg-baseproc/", None),
75
76
  "ezmsg.learn": ("https://www.ezmsg.org/ezmsg-learn/", None),
76
77
  "ezmsg.event": ("https://www.ezmsg.org/ezmsg-event/", None),
77
78
  "ezmsg.lsl": ("https://www.ezmsg.org/ezmsg-lsl/", None),
@@ -0,0 +1,58 @@
1
+ ## Signal Processor Base Classes
2
+
3
+ The signal processors in `ezmsg-sigproc` are built on top of the base processor classes from `ezmsg-baseproc`. For comprehensive documentation on the processor architecture, including protocols, base classes, and implementation patterns, see the [ezmsg-baseproc documentation](https://www.ezmsg.org/ezmsg-baseproc/guides/ProcessorsBase.html).
4
+
5
+ ### Quick Reference
6
+
7
+ The base classes provide a consistent pattern for building message processors:
8
+
9
+ * **Processors** - Transform input messages to output messages
10
+ * **Producers** - Generate output messages without requiring input
11
+ * **Consumers** - Accept input messages without producing output
12
+ * **Transformers** - A specific type of processor with typed input/output
13
+ * **Stateful variants** - Processors that maintain state across invocations
14
+ * **Adaptive transformers** - Transformers that can be trained via `partial_fit`
15
+ * **Composite processors** - Chain multiple processors together efficiently
16
+
17
+ ### Signal Processing Example
18
+
19
+ Here's an example of a signal processing transformer using `AxisArray`:
20
+
21
+ ```Python
22
+ import ezmsg.core as ez
23
+ from ezmsg.util.messages.axisarray import AxisArray, replace
24
+ from ezmsg.baseproc import BaseTransformer, BaseTransformerUnit
25
+
26
+
27
+ class ScaleTransformerSettings(ez.Settings):
28
+ scale: float = 1.0
29
+
30
+
31
+ class ScaleTransformer(BaseTransformer[ScaleTransformerSettings, AxisArray, AxisArray]):
32
+ def _process(self, message: AxisArray) -> AxisArray:
33
+ return replace(message, data=message.data * self.settings.scale)
34
+
35
+
36
+ class ScaleUnit(BaseTransformerUnit[
37
+ ScaleTransformerSettings,
38
+ AxisArray,
39
+ AxisArray,
40
+ ScaleTransformer,
41
+ ]):
42
+ SETTINGS = ScaleTransformerSettings
43
+ ```
44
+
45
+ ### Existing Signal Processors
46
+
47
+ For examples of signal processing implementations, see the processors in `ezmsg.sigproc`:
48
+
49
+ * **Filtering** - `ChebyshevFilterTransformer`, `CombFilterTransformer`, etc.
50
+ * **Spectral** - `SpectrogramTransformer`, `SpectrumTransformer`, `WaveletTransformer`
51
+ * **Resampling** - `DownsampleTransformer`, `DecimateTransformer`, `ResampleTransformer`
52
+ * **Windowing** - `WindowTransformer`, `AggregateTransformer`
53
+ * **Math** - `ScalerTransformer`, `LogTransformer`, `AbsTransformer`, `DifferenceTransformer`
54
+
55
+ ### Learn More
56
+
57
+ * [Processor Base Classes (ezmsg-baseproc)](https://www.ezmsg.org/ezmsg-baseproc/guides/ProcessorsBase.html) - Full documentation on the processor architecture
58
+ * [API Reference](../api/index) - Complete API documentation for ezmsg-sigproc
@@ -0,0 +1,6 @@
1
+ How to efficiently chain multiple signal processors in ezmsg?
2
+ #############################################################
3
+
4
+ For general composite processor implementation guidance, see the `ezmsg-baseproc documentation <https://www.ezmsg.org/ezmsg-baseproc/guides/ProcessorsBase.html>`_.
5
+
6
+ (under construction)
@@ -0,0 +1,8 @@
1
+ How to write a signal processor in ezmsg?
2
+ #########################################
3
+
4
+ For general processor implementation guidance, see the `ezmsg-baseproc documentation <https://www.ezmsg.org/ezmsg-baseproc/guides/ProcessorsBase.html>`_.
5
+
6
+ For signal processing specific patterns, see the existing processors in ``ezmsg.sigproc`` as examples.
7
+
8
+ (under construction)
@@ -0,0 +1,8 @@
1
+ How to implement a stateful signal processor in ezmsg?
2
+ ######################################################
3
+
4
+ For general stateful processor implementation guidance, see the `ezmsg-baseproc documentation <https://www.ezmsg.org/ezmsg-baseproc/guides/ProcessorsBase.html>`_.
5
+
6
+ For signal processing specific patterns using stateful processors, see implementations like ``ChebyshevFilterTransformer`` and ``WindowTransformer`` as examples.
7
+
8
+ (under construction)
@@ -0,0 +1,41 @@
1
+ How to turn a signal processor into an ``ezmsg`` Unit?
2
+ ######################################################
3
+
4
+ For general guidance on converting processors to ezmsg Units, see the `ezmsg-baseproc documentation <https://www.ezmsg.org/ezmsg-baseproc/guides/ProcessorsBase.html#implementing-a-custom-ezmsg-unit>`_.
5
+
6
+ Example with Signal Processing
7
+ ------------------------------
8
+
9
+ To convert a signal processor to an ``ezmsg`` Unit:
10
+
11
+ 1. **Define the Processor**: Create a class that inherits from the appropriate base class (e.g., ``BaseTransformer``, ``BaseStatefulTransformer``).
12
+ 2. **Implement the Processing Logic**: Override the ``_process`` method to implement the signal processing logic.
13
+ 3. **Create the Unit**: Inherit from the appropriate Unit base class (e.g., ``BaseTransformerUnit``).
14
+
15
+ .. code-block:: python
16
+
17
+ import ezmsg.core as ez
18
+ from ezmsg.util.messages.axisarray import AxisArray
19
+ from ezmsg.baseproc import BaseTransformer, BaseTransformerUnit
20
+
21
+
22
+ class MyProcessorSettings(ez.Settings):
23
+ # Your settings here
24
+ pass
25
+
26
+
27
+ class MyProcessor(BaseTransformer[MyProcessorSettings, AxisArray, AxisArray]):
28
+ def _process(self, message: AxisArray) -> AxisArray:
29
+ # Your signal processing logic here
30
+ return message
31
+
32
+
33
+ class MyUnit(BaseTransformerUnit[
34
+ MyProcessorSettings,
35
+ AxisArray,
36
+ AxisArray,
37
+ MyProcessor,
38
+ ]):
39
+ SETTINGS = MyProcessorSettings
40
+
41
+ (under construction)
@@ -0,0 +1,19 @@
1
+ Base Processors
2
+ ===============
3
+
4
+ The base processor classes are provided by the ``ezmsg-baseproc`` package and re-exported from ``ezmsg.sigproc.base`` for backwards compatibility.
5
+
6
+ For detailed documentation on the base processor architecture, see the `ezmsg-baseproc documentation <https://www.ezmsg.org/ezmsg-baseproc/>`_.
7
+
8
+ .. note::
9
+ New code should import directly from ``ezmsg.baseproc`` instead of ``ezmsg.sigproc.base``.
10
+
11
+ API Reference
12
+ -------------
13
+
14
+ The following classes are re-exported from ``ezmsg.baseproc``:
15
+
16
+ .. automodule:: ezmsg.sigproc.base
17
+ :members:
18
+ :show-inheritance:
19
+ :imported-members:
@@ -13,6 +13,7 @@ requires-python = ">=3.10.15"
13
13
  dynamic = ["version"]
14
14
  dependencies = [
15
15
  "array-api-compat>=1.11.1",
16
+ "ezmsg-baseproc>=1.0.3",
16
17
  "ezmsg>=3.6.0",
17
18
  "numba>=0.61.0",
18
19
  "numpy>=1.26.0",
@@ -64,5 +65,24 @@ version-file = "src/ezmsg/sigproc/__version__.py"
64
65
  packages = ["src/ezmsg"]
65
66
 
66
67
  [tool.pytest.ini_options]
68
+ asyncio_mode = "auto"
69
+ asyncio_default_fixture_loop_scope = "function"
67
70
  norecursedirs = "tests/helpers"
68
71
  addopts = "-p no:warnings"
72
+
73
+ [tool.ruff]
74
+ line-length = 120
75
+ target-version = "py310"
76
+ # Exclude auto-generated files
77
+ exclude = ["*/__version__.py"]
78
+
79
+ [tool.ruff.lint]
80
+ select = ["E", "F", "I", "W"]
81
+
82
+ [tool.ruff.lint.isort]
83
+ known-first-party = ["ezmsg.sigproc"]
84
+ known-third-party = ["ezmsg", "ezmsg.baseproc"]
85
+
86
+ [tool.uv.sources]
87
+ # Uncomment to use development version of ezmsg from git
88
+ #ezmsg = { git = "https://github.com/ezmsg-org/ezmsg.git", branch = "dev" }
@@ -28,7 +28,7 @@ version_tuple: VERSION_TUPLE
28
28
  commit_id: COMMIT_ID
29
29
  __commit_id__: COMMIT_ID
30
30
 
31
- __version__ = version = '2.5.0'
32
- __version_tuple__ = version_tuple = (2, 5, 0)
31
+ __version__ = version = '2.6.0'
32
+ __version_tuple__ = version_tuple = (2, 6, 0)
33
33
 
34
34
  __commit_id__ = commit_id = None
@@ -1,10 +1,10 @@
1
- import scipy.special
2
1
  import ezmsg.core as ez
2
+ import scipy.special
3
3
  from ezmsg.util.messages.axisarray import AxisArray
4
4
  from ezmsg.util.messages.util import replace
5
5
 
6
- from .spectral import OptionsEnum
7
6
  from .base import BaseTransformer, BaseTransformerUnit
7
+ from .spectral import OptionsEnum
8
8
 
9
9
 
10
10
  class ActivationFunction(OptionsEnum):
@@ -50,20 +50,14 @@ class ActivationTransformer(BaseTransformer[ActivationSettings, AxisArray, AxisA
50
50
  # str type handling
51
51
  function = self.settings.function.lower()
52
52
  if function not in ActivationFunction.options():
53
- raise ValueError(
54
- f"Unrecognized activation function {function}. Must be one of {ACTIVATIONS.keys()}"
55
- )
56
- function = list(ACTIVATIONS.keys())[
57
- ActivationFunction.options().index(function)
58
- ]
53
+ raise ValueError(f"Unrecognized activation function {function}. Must be one of {ACTIVATIONS.keys()}")
54
+ function = list(ACTIVATIONS.keys())[ActivationFunction.options().index(function)]
59
55
  func = ACTIVATIONS[function]
60
56
 
61
57
  return replace(message, data=func(message.data))
62
58
 
63
59
 
64
- class Activation(
65
- BaseTransformerUnit[ActivationSettings, AxisArray, AxisArray, ActivationTransformer]
66
- ):
60
+ class Activation(BaseTransformerUnit[ActivationSettings, AxisArray, AxisArray, ActivationTransformer]):
67
61
  SETTINGS = ActivationSettings
68
62
 
69
63
 
@@ -1,11 +1,11 @@
1
+ import ezmsg.core as ez
1
2
  import numpy as np
2
3
  import numpy.typing as npt
3
4
  import scipy.signal
4
- import ezmsg.core as ez
5
5
  from ezmsg.util.messages.axisarray import AxisArray, CoordinateAxis
6
6
  from ezmsg.util.messages.util import replace
7
7
 
8
- from .base import processor_state, BaseStatefulTransformer
8
+ from .base import BaseStatefulTransformer, processor_state
9
9
 
10
10
 
11
11
  class AdaptiveLatticeNotchFilterSettings(ez.Settings):
@@ -76,9 +76,7 @@ class AdaptiveLatticeNotchFilterTransformer(
76
76
 
77
77
  fs = 1 / message.axes[self.settings.axis].gain
78
78
  init_f = (
79
- self.settings.init_notch_freq
80
- if self.settings.init_notch_freq is not None
81
- else 0.07178314656435313 * fs
79
+ self.settings.init_notch_freq if self.settings.init_notch_freq is not None else 0.07178314656435313 * fs
82
80
  )
83
81
  init_omega = init_f * (2 * np.pi) / fs
84
82
  init_k1 = -np.cos(init_omega)
@@ -91,9 +89,7 @@ class AdaptiveLatticeNotchFilterTransformer(
91
89
  self._state.k1 = init_k1 + np.zeros(sample_shape, dtype=float)
92
90
  self._state.freq_template = CoordinateAxis(
93
91
  data=np.zeros((0,) + sample_shape, dtype=float),
94
- dims=[self.settings.axis]
95
- + message.dims[:ax_idx]
96
- + message.dims[ax_idx + 1 :],
92
+ dims=[self.settings.axis] + message.dims[:ax_idx] + message.dims[ax_idx + 1 :],
97
93
  unit="Hz",
98
94
  )
99
95
 
@@ -147,9 +143,7 @@ class AdaptiveLatticeNotchFilterTransformer(
147
143
  for ix, k in enumerate(self._state.k1.flatten()):
148
144
  # Filter to get s_n (notch filter state)
149
145
  a_s = [1, k * gamma_plus_1, gamma]
150
- s_n[:, ix], self._state.zi[:, ix] = scipy.signal.lfilter(
151
- [1], a_s, _x[:, ix], zi=self._state.zi[:, ix]
152
- )
146
+ s_n[:, ix], self._state.zi[:, ix] = scipy.signal.lfilter([1], a_s, _x[:, ix], zi=self._state.zi[:, ix])
153
147
 
154
148
  # Apply output filter to get y_out
155
149
  b_y = [1, 2 * k, 1]
@@ -159,17 +153,11 @@ class AdaptiveLatticeNotchFilterTransformer(
159
153
  s_n_reshaped = s_n.reshape((s_n.shape[0],) + x_data.shape[1:])
160
154
  s_final = s_n_reshaped[-1] # Current s_n
161
155
  s_final_1 = s_n_reshaped[-2] # s_n_1
162
- s_final_2 = (
163
- s_n_reshaped[-3] if len(s_n_reshaped) > 2 else self._state.s_history[0]
164
- ) # s_n_2
156
+ s_final_2 = s_n_reshaped[-3] if len(s_n_reshaped) > 2 else self._state.s_history[0] # s_n_2
165
157
 
166
158
  # Update p and q using final values
167
- self._state.p = eta * self._state.p + one_minus_eta * (
168
- s_final_1 * (s_final + s_final_2)
169
- )
170
- self._state.q = eta * self._state.q + one_minus_eta * (
171
- 2 * (s_final_1 * s_final_1)
172
- )
159
+ self._state.p = eta * self._state.p + one_minus_eta * (s_final_1 * (s_final + s_final_2))
160
+ self._state.q = eta * self._state.q + one_minus_eta * (2 * (s_final_1 * s_final_1))
173
161
 
174
162
  # Update reflection coefficient
175
163
  new_k1 = -self._state.p / (self._state.q + 1e-8) # Avoid division by zero
@@ -199,17 +187,11 @@ class AdaptiveLatticeNotchFilterTransformer(
199
187
  y_out[sample_ix] = s_n + 2 * self._state.k1 * s_n_1 + s_n_2
200
188
 
201
189
  # Update filter parameters
202
- self._state.p = eta * self._state.p + one_minus_eta * (
203
- s_n_1 * (s_n + s_n_2)
204
- )
205
- self._state.q = eta * self._state.q + one_minus_eta * (
206
- 2 * (s_n_1 * s_n_1)
207
- )
190
+ self._state.p = eta * self._state.p + one_minus_eta * (s_n_1 * (s_n + s_n_2))
191
+ self._state.q = eta * self._state.q + one_minus_eta * (2 * (s_n_1 * s_n_1))
208
192
 
209
193
  # Update reflection coefficient
210
- new_k1 = -self._state.p / (
211
- self._state.q + 1e-8
212
- ) # Avoid division by zero
194
+ new_k1 = -self._state.p / (self._state.q + 1e-8) # Avoid division by zero
213
195
  new_k1 = np.clip(new_k1, -1, 1) # Clip to prevent instability
214
196
  self._state.k1 = mu * self._state.k1 + one_minus_mu * new_k1 # Smoothed
215
197
 
@@ -1,16 +1,16 @@
1
1
  import os
2
2
  from pathlib import Path
3
3
 
4
+ import ezmsg.core as ez
4
5
  import numpy as np
5
6
  import numpy.typing as npt
6
- import ezmsg.core as ez
7
7
  from ezmsg.util.messages.axisarray import AxisArray, AxisBase
8
8
  from ezmsg.util.messages.util import replace
9
9
 
10
10
  from .base import (
11
11
  BaseStatefulTransformer,
12
- BaseTransformerUnit,
13
12
  BaseTransformer,
13
+ BaseTransformerUnit,
14
14
  processor_state,
15
15
  )
16
16
 
@@ -38,15 +38,12 @@ class AffineTransformState:
38
38
 
39
39
 
40
40
  class AffineTransformTransformer(
41
- BaseStatefulTransformer[
42
- AffineTransformSettings, AxisArray, AxisArray, AffineTransformState
43
- ]
41
+ BaseStatefulTransformer[AffineTransformSettings, AxisArray, AxisArray, AffineTransformState]
44
42
  ):
45
43
  def __call__(self, message: AxisArray) -> AxisArray:
46
44
  # Override __call__ so we can shortcut if weights are None.
47
45
  if self.settings.weights is None or (
48
- isinstance(self.settings.weights, str)
49
- and self.settings.weights == "passthrough"
46
+ isinstance(self.settings.weights, str) and self.settings.weights == "passthrough"
50
47
  ):
51
48
  return message
52
49
  return super().__call__(message)
@@ -68,18 +65,12 @@ class AffineTransformTransformer(
68
65
  self._state.weights = weights
69
66
 
70
67
  axis = self.settings.axis or message.dims[-1]
71
- if (
72
- axis in message.axes
73
- and hasattr(message.axes[axis], "data")
74
- and weights.shape[0] != weights.shape[1]
75
- ):
68
+ if axis in message.axes and hasattr(message.axes[axis], "data") and weights.shape[0] != weights.shape[1]:
76
69
  in_labels = message.axes[axis].data
77
70
  new_labels = []
78
71
  n_in, n_out = weights.shape
79
72
  if len(in_labels) != n_in:
80
- ez.logger.warning(
81
- f"Received {len(in_labels)} for {n_in} inputs. Check upstream labels."
82
- )
73
+ ez.logger.warning(f"Received {len(in_labels)} for {n_in} inputs. Check upstream labels.")
83
74
  else:
84
75
  b_filled_outputs = np.any(weights, axis=0)
85
76
  b_used_inputs = np.any(weights, axis=1)
@@ -97,9 +88,7 @@ class AffineTransformTransformer(
97
88
  elif np.all(b_filled_outputs):
98
89
  new_labels = np.array(in_labels)[b_used_inputs]
99
90
 
100
- self._state.new_axis = replace(
101
- message.axes[axis], data=np.array(new_labels)
102
- )
91
+ self._state.new_axis = replace(message.axes[axis], data=np.array(new_labels))
103
92
 
104
93
  def _process(self, message: AxisArray) -> AxisArray:
105
94
  axis = self.settings.axis or message.dims[-1]
@@ -110,9 +99,7 @@ class AffineTransformTransformer(
110
99
  # The weights are stacked A|B where A is the transform and B is a single row
111
100
  # in the equation y = Ax + B. This supports NeuroKey's weights matrices.
112
101
  sample_shape = data.shape[:axis_idx] + (1,) + data.shape[axis_idx + 1 :]
113
- data = np.concatenate(
114
- (data, np.ones(sample_shape).astype(data.dtype)), axis=axis_idx
115
- )
102
+ data = np.concatenate((data, np.ones(sample_shape).astype(data.dtype)), axis=axis_idx)
116
103
 
117
104
  if axis_idx in [-1, len(message.dims) - 1]:
118
105
  data = np.matmul(data, self._state.weights)
@@ -128,11 +115,7 @@ class AffineTransformTransformer(
128
115
  return replace(message, **replace_kwargs)
129
116
 
130
117
 
131
- class AffineTransform(
132
- BaseTransformerUnit[
133
- AffineTransformSettings, AxisArray, AxisArray, AffineTransformTransformer
134
- ]
135
- ):
118
+ class AffineTransform(BaseTransformerUnit[AffineTransformSettings, AxisArray, AxisArray, AffineTransformTransformer]):
136
119
  SETTINGS = AffineTransformSettings
137
120
 
138
121
 
@@ -153,9 +136,7 @@ def affine_transform(
153
136
  :obj:`AffineTransformTransformer`.
154
137
  """
155
138
  return AffineTransformTransformer(
156
- AffineTransformSettings(
157
- weights=weights, axis=axis, right_multiply=right_multiply
158
- )
139
+ AffineTransformSettings(weights=weights, axis=axis, right_multiply=right_multiply)
159
140
  )
160
141
 
161
142
 
@@ -178,9 +159,7 @@ class CommonRereferenceSettings(ez.Settings):
178
159
  """Set False to exclude each channel from participating in the calculation of its reference."""
179
160
 
180
161
 
181
- class CommonRereferenceTransformer(
182
- BaseTransformer[CommonRereferenceSettings, AxisArray, AxisArray]
183
- ):
162
+ class CommonRereferenceTransformer(BaseTransformer[CommonRereferenceSettings, AxisArray, AxisArray]):
184
163
  def _process(self, message: AxisArray) -> AxisArray:
185
164
  if self.settings.mode == "passthrough":
186
165
  return message
@@ -188,9 +167,7 @@ class CommonRereferenceTransformer(
188
167
  axis = self.settings.axis or message.dims[-1]
189
168
  axis_idx = message.get_axis_idx(axis)
190
169
 
191
- func = {"mean": np.mean, "median": np.median, "passthrough": zeros_for_noop}[
192
- self.settings.mode
193
- ]
170
+ func = {"mean": np.mean, "median": np.median, "passthrough": zeros_for_noop}[self.settings.mode]
194
171
 
195
172
  ref_data = func(message.data, axis=axis_idx, keepdims=True)
196
173
 
@@ -213,9 +190,7 @@ class CommonRereferenceTransformer(
213
190
 
214
191
 
215
192
  class CommonRereference(
216
- BaseTransformerUnit[
217
- CommonRereferenceSettings, AxisArray, AxisArray, CommonRereferenceTransformer
218
- ]
193
+ BaseTransformerUnit[CommonRereferenceSettings, AxisArray, AxisArray, CommonRereferenceTransformer]
219
194
  ):
220
195
  SETTINGS = CommonRereferenceSettings
221
196
 
@@ -1,23 +1,23 @@
1
- from array_api_compat import get_namespace
2
1
  import typing
3
2
 
3
+ import ezmsg.core as ez
4
4
  import numpy as np
5
5
  import numpy.typing as npt
6
- import ezmsg.core as ez
6
+ from array_api_compat import get_namespace
7
7
  from ezmsg.util.messages.axisarray import (
8
8
  AxisArray,
9
- slice_along_axis,
10
9
  AxisBase,
11
10
  replace,
11
+ slice_along_axis,
12
12
  )
13
13
 
14
- from .spectral import OptionsEnum
15
14
  from .base import (
16
- BaseTransformer,
17
15
  BaseStatefulTransformer,
16
+ BaseTransformer,
18
17
  BaseTransformerUnit,
19
18
  processor_state,
20
19
  )
20
+ from .spectral import OptionsEnum
21
21
 
22
22
 
23
23
  class AggregationFunction(OptionsEnum):
@@ -89,9 +89,7 @@ class RangedAggregateState:
89
89
 
90
90
 
91
91
  class RangedAggregateTransformer(
92
- BaseStatefulTransformer[
93
- RangedAggregateSettings, AxisArray, AxisArray, RangedAggregateState
94
- ]
92
+ BaseStatefulTransformer[RangedAggregateSettings, AxisArray, AxisArray, RangedAggregateState]
95
93
  ):
96
94
  def __call__(self, message: AxisArray) -> AxisArray:
97
95
  # Override for shortcut passthrough mode.
@@ -118,16 +116,12 @@ class RangedAggregateTransformer(
118
116
  if hasattr(target_axis, "data"):
119
117
  self._state.ax_vec = target_axis.data
120
118
  else:
121
- self._state.ax_vec = target_axis.value(
122
- np.arange(message.data.shape[ax_idx])
123
- )
119
+ self._state.ax_vec = target_axis.value(np.arange(message.data.shape[ax_idx]))
124
120
 
125
121
  ax_dat = []
126
122
  slices = []
127
123
  for start, stop in self.settings.bands:
128
- inds = np.where(
129
- np.logical_and(self._state.ax_vec >= start, self._state.ax_vec <= stop)
130
- )[0]
124
+ inds = np.where(np.logical_and(self._state.ax_vec >= start, self._state.ax_vec <= stop))[0]
131
125
  slices.append(np.s_[inds[0] : inds[-1] + 1])
132
126
  if hasattr(target_axis, "data"):
133
127
  if self._state.ax_vec.dtype.type is np.str_:
@@ -164,8 +158,7 @@ class RangedAggregateTransformer(
164
158
  ]
165
159
  else:
166
160
  out_data = [
167
- agg_func(slice_along_axis(message.data, sl, axis=ax_idx), axis=ax_idx)
168
- for sl in self._state.slices
161
+ agg_func(slice_along_axis(message.data, sl, axis=ax_idx), axis=ax_idx) for sl in self._state.slices
169
162
  ]
170
163
 
171
164
  msg_out = replace(
@@ -187,11 +180,7 @@ class RangedAggregateTransformer(
187
180
  return msg_out
188
181
 
189
182
 
190
- class RangedAggregate(
191
- BaseTransformerUnit[
192
- RangedAggregateSettings, AxisArray, AxisArray, RangedAggregateTransformer
193
- ]
194
- ):
183
+ class RangedAggregate(BaseTransformerUnit[RangedAggregateSettings, AxisArray, AxisArray, RangedAggregateTransformer]):
195
184
  SETTINGS = RangedAggregateSettings
196
185
 
197
186
 
@@ -212,9 +201,7 @@ def ranged_aggregate(
212
201
  Returns:
213
202
  :obj:`RangedAggregateTransformer`
214
203
  """
215
- return RangedAggregateTransformer(
216
- RangedAggregateSettings(axis=axis, bands=bands, operation=operation)
217
- )
204
+ return RangedAggregateTransformer(RangedAggregateSettings(axis=axis, bands=bands, operation=operation))
218
205
 
219
206
 
220
207
  class AggregateSettings(ez.Settings):
@@ -242,9 +229,7 @@ class AggregateTransformer(BaseTransformer[AggregateSettings, AxisArray, AxisArr
242
229
  op = self.settings.operation
243
230
 
244
231
  if op == AggregationFunction.NONE:
245
- raise ValueError(
246
- "AggregationFunction.NONE is not supported for full-axis aggregation"
247
- )
232
+ raise ValueError("AggregationFunction.NONE is not supported for full-axis aggregation")
248
233
 
249
234
  if op == AggregationFunction.TRAPEZOID:
250
235
  # Trapezoid integration requires x-coordinates
@@ -276,9 +261,7 @@ class AggregateTransformer(BaseTransformer[AggregateSettings, AxisArray, AxisArr
276
261
  )
277
262
 
278
263
 
279
- class AggregateUnit(
280
- BaseTransformerUnit[AggregateSettings, AxisArray, AxisArray, AggregateTransformer]
281
- ):
264
+ class AggregateUnit(BaseTransformerUnit[AggregateSettings, AxisArray, AxisArray, AggregateTransformer]):
282
265
  """Unit that aggregates an entire axis using a specified operation."""
283
266
 
284
267
  SETTINGS = AggregateSettings