ezmsg-baseproc 1.0.3__tar.gz → 1.2.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 (46) hide show
  1. {ezmsg_baseproc-1.0.3 → ezmsg_baseproc-1.2.0}/PKG-INFO +19 -22
  2. {ezmsg_baseproc-1.0.3 → ezmsg_baseproc-1.2.0}/README.md +18 -21
  3. {ezmsg_baseproc-1.0.3 → ezmsg_baseproc-1.2.0}/docs/source/guides/ProcessorsBase.md +25 -20
  4. ezmsg_baseproc-1.2.0/docs/source/guides/how-tos/processors/clockdriven.rst +224 -0
  5. {ezmsg_baseproc-1.0.3 → ezmsg_baseproc-1.2.0}/docs/source/guides/how-tos/processors/content-processors.rst +1 -0
  6. ezmsg_baseproc-1.2.0/docs/source/index.md +18 -0
  7. {ezmsg_baseproc-1.0.3 → ezmsg_baseproc-1.2.0}/src/ezmsg/baseproc/__init__.py +42 -0
  8. {ezmsg_baseproc-1.0.3 → ezmsg_baseproc-1.2.0}/src/ezmsg/baseproc/__version__.py +2 -2
  9. ezmsg_baseproc-1.2.0/src/ezmsg/baseproc/clock.py +109 -0
  10. ezmsg_baseproc-1.2.0/src/ezmsg/baseproc/clockdriven.py +179 -0
  11. ezmsg_baseproc-1.2.0/src/ezmsg/baseproc/counter.py +67 -0
  12. {ezmsg_baseproc-1.0.3 → ezmsg_baseproc-1.2.0}/src/ezmsg/baseproc/units.py +48 -1
  13. {ezmsg_baseproc-1.0.3 → ezmsg_baseproc-1.2.0}/src/ezmsg/baseproc/util/typeresolution.py +9 -1
  14. ezmsg_baseproc-1.2.0/tests/test_clock.py +83 -0
  15. ezmsg_baseproc-1.2.0/tests/test_clockdriven.py +373 -0
  16. ezmsg_baseproc-1.2.0/tests/test_counter.py +180 -0
  17. ezmsg_baseproc-1.0.3/docs/source/index.rst +0 -87
  18. {ezmsg_baseproc-1.0.3 → ezmsg_baseproc-1.2.0}/.github/workflows/docs.yml +0 -0
  19. {ezmsg_baseproc-1.0.3 → ezmsg_baseproc-1.2.0}/.github/workflows/python-publish.yml +0 -0
  20. {ezmsg_baseproc-1.0.3 → ezmsg_baseproc-1.2.0}/.github/workflows/python-tests.yml +0 -0
  21. {ezmsg_baseproc-1.0.3 → ezmsg_baseproc-1.2.0}/.gitignore +0 -0
  22. {ezmsg_baseproc-1.0.3 → ezmsg_baseproc-1.2.0}/.pre-commit-config.yaml +0 -0
  23. {ezmsg_baseproc-1.0.3 → ezmsg_baseproc-1.2.0}/LICENSE +0 -0
  24. {ezmsg_baseproc-1.0.3 → ezmsg_baseproc-1.2.0}/docs/Makefile +0 -0
  25. {ezmsg_baseproc-1.0.3 → ezmsg_baseproc-1.2.0}/docs/make.bat +0 -0
  26. {ezmsg_baseproc-1.0.3 → ezmsg_baseproc-1.2.0}/docs/source/_templates/autosummary/module.rst +0 -0
  27. {ezmsg_baseproc-1.0.3 → ezmsg_baseproc-1.2.0}/docs/source/api/index.rst +0 -0
  28. {ezmsg_baseproc-1.0.3 → ezmsg_baseproc-1.2.0}/docs/source/conf.py +0 -0
  29. {ezmsg_baseproc-1.0.3 → ezmsg_baseproc-1.2.0}/docs/source/guides/how-tos/processors/adaptive.rst +0 -0
  30. {ezmsg_baseproc-1.0.3 → ezmsg_baseproc-1.2.0}/docs/source/guides/how-tos/processors/checkpoint.rst +0 -0
  31. {ezmsg_baseproc-1.0.3 → ezmsg_baseproc-1.2.0}/docs/source/guides/how-tos/processors/composite.rst +0 -0
  32. {ezmsg_baseproc-1.0.3 → ezmsg_baseproc-1.2.0}/docs/source/guides/how-tos/processors/processor.rst +0 -0
  33. {ezmsg_baseproc-1.0.3 → ezmsg_baseproc-1.2.0}/docs/source/guides/how-tos/processors/standalone.rst +0 -0
  34. {ezmsg_baseproc-1.0.3 → ezmsg_baseproc-1.2.0}/docs/source/guides/how-tos/processors/stateful.rst +0 -0
  35. {ezmsg_baseproc-1.0.3 → ezmsg_baseproc-1.2.0}/docs/source/guides/how-tos/processors/unit.rst +0 -0
  36. {ezmsg_baseproc-1.0.3 → ezmsg_baseproc-1.2.0}/pyproject.toml +0 -0
  37. {ezmsg_baseproc-1.0.3 → ezmsg_baseproc-1.2.0}/src/ezmsg/baseproc/composite.py +0 -0
  38. {ezmsg_baseproc-1.0.3 → ezmsg_baseproc-1.2.0}/src/ezmsg/baseproc/processor.py +0 -0
  39. {ezmsg_baseproc-1.0.3 → ezmsg_baseproc-1.2.0}/src/ezmsg/baseproc/protocols.py +0 -0
  40. {ezmsg_baseproc-1.0.3 → ezmsg_baseproc-1.2.0}/src/ezmsg/baseproc/stateful.py +0 -0
  41. {ezmsg_baseproc-1.0.3 → ezmsg_baseproc-1.2.0}/src/ezmsg/baseproc/util/__init__.py +0 -0
  42. {ezmsg_baseproc-1.0.3 → ezmsg_baseproc-1.2.0}/src/ezmsg/baseproc/util/asio.py +0 -0
  43. {ezmsg_baseproc-1.0.3 → ezmsg_baseproc-1.2.0}/src/ezmsg/baseproc/util/message.py +0 -0
  44. {ezmsg_baseproc-1.0.3 → ezmsg_baseproc-1.2.0}/src/ezmsg/baseproc/util/profile.py +0 -0
  45. {ezmsg_baseproc-1.0.3 → ezmsg_baseproc-1.2.0}/tests/test_baseproc.py +0 -0
  46. {ezmsg_baseproc-1.0.3 → ezmsg_baseproc-1.2.0}/tests/test_profile.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: ezmsg-baseproc
3
- Version: 1.0.3
3
+ Version: 1.2.0
4
4
  Summary: Base processor classes and protocols for ezmsg signal processing pipelines
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
@@ -12,7 +12,7 @@ Description-Content-Type: text/markdown
12
12
 
13
13
  # ezmsg-baseproc
14
14
 
15
- Base processor classes and protocols for building signal processing pipelines in [ezmsg](https://github.com/ezmsg-org/ezmsg).
15
+ Base processor classes and protocols for building message-processing components in [ezmsg](https://github.com/ezmsg-org/ezmsg).
16
16
 
17
17
  ## Installation
18
18
 
@@ -20,30 +20,26 @@ Base processor classes and protocols for building signal processing pipelines in
20
20
  pip install ezmsg-baseproc
21
21
  ```
22
22
 
23
- ## Overview
23
+ Or install the latest development version:
24
24
 
25
- This package provides the foundational processor architecture for ezmsg signal processing:
25
+ ```bash
26
+ pip install git+https://github.com/ezmsg-org/ezmsg-baseproc@dev
27
+ ```
26
28
 
27
- - **Protocols** - Type definitions for processors, transformers, consumers, and producers
28
- - **Base Classes** - Abstract base classes for building stateless and stateful processors
29
- - **Composite Processors** - Classes for chaining processors into pipelines
30
- - **Unit Wrappers** - ezmsg Unit base classes that wrap processors for graph integration
29
+ ## Overview
31
30
 
32
- ## Module Structure
31
+ ``ezmsg-baseproc`` provides abstract base classes for creating message processors that can be used both standalone and within ezmsg pipelines. The package offers a consistent pattern for building:
33
32
 
34
- ```
35
- ezmsg.baseproc/
36
- ├── protocols.py # Protocol definitions and type variables
37
- ├── processor.py # Base non-stateful processors
38
- ├── stateful.py # Stateful processor base classes
39
- ├── composite.py # CompositeProcessor and CompositeProducer
40
- ├── units.py # ezmsg Unit wrappers
41
- └── util/
42
- ├── asio.py # Async/sync utilities
43
- ├── message.py # SampleMessage definitions
44
- ├── profile.py # Profiling decorators
45
- └── typeresolution.py # Type resolution helpers
46
- ```
33
+ * **Protocols** - Type definitions for processors, transformers, consumers, and producers
34
+ * **Processors** - Transform input messages to output messages
35
+ * **Producers** - Generate output messages without requiring input
36
+ * **Consumers** - Accept input messages without producing output
37
+ * **Transformers** - A specific type of processor with typed input/output
38
+ * **Stateful variants** - Processors that maintain state across invocations
39
+ * **Adaptive transformers** - Transformers that can be trained via ``partial_fit``
40
+ * **Composite processors** - Chain multiple processors together efficiently
41
+
42
+ All base classes support both synchronous and asynchronous operation, making them suitable for offline analysis and real-time streaming applications.
47
43
 
48
44
  ## Usage
49
45
 
@@ -100,6 +96,7 @@ We use [`uv`](https://docs.astral.sh/uv/getting-started/installation/) for devel
100
96
  2. Clone and cd into the repository
101
97
  3. Run `uv sync` to create a `.venv` and install dependencies
102
98
  4. Run `uv run pytest tests` to run tests
99
+ 5. (Optional) Install pre-commit hooks: `uv run pre-commit install`
103
100
 
104
101
  ## License
105
102
 
@@ -1,6 +1,6 @@
1
1
  # ezmsg-baseproc
2
2
 
3
- Base processor classes and protocols for building signal processing pipelines in [ezmsg](https://github.com/ezmsg-org/ezmsg).
3
+ Base processor classes and protocols for building message-processing components in [ezmsg](https://github.com/ezmsg-org/ezmsg).
4
4
 
5
5
  ## Installation
6
6
 
@@ -8,30 +8,26 @@ Base processor classes and protocols for building signal processing pipelines in
8
8
  pip install ezmsg-baseproc
9
9
  ```
10
10
 
11
- ## Overview
11
+ Or install the latest development version:
12
12
 
13
- This package provides the foundational processor architecture for ezmsg signal processing:
13
+ ```bash
14
+ pip install git+https://github.com/ezmsg-org/ezmsg-baseproc@dev
15
+ ```
14
16
 
15
- - **Protocols** - Type definitions for processors, transformers, consumers, and producers
16
- - **Base Classes** - Abstract base classes for building stateless and stateful processors
17
- - **Composite Processors** - Classes for chaining processors into pipelines
18
- - **Unit Wrappers** - ezmsg Unit base classes that wrap processors for graph integration
17
+ ## Overview
19
18
 
20
- ## Module Structure
19
+ ``ezmsg-baseproc`` provides abstract base classes for creating message processors that can be used both standalone and within ezmsg pipelines. The package offers a consistent pattern for building:
21
20
 
22
- ```
23
- ezmsg.baseproc/
24
- ├── protocols.py # Protocol definitions and type variables
25
- ├── processor.py # Base non-stateful processors
26
- ├── stateful.py # Stateful processor base classes
27
- ├── composite.py # CompositeProcessor and CompositeProducer
28
- ├── units.py # ezmsg Unit wrappers
29
- └── util/
30
- ├── asio.py # Async/sync utilities
31
- ├── message.py # SampleMessage definitions
32
- ├── profile.py # Profiling decorators
33
- └── typeresolution.py # Type resolution helpers
34
- ```
21
+ * **Protocols** - Type definitions for processors, transformers, consumers, and producers
22
+ * **Processors** - Transform input messages to output messages
23
+ * **Producers** - Generate output messages without requiring input
24
+ * **Consumers** - Accept input messages without producing output
25
+ * **Transformers** - A specific type of processor with typed input/output
26
+ * **Stateful variants** - Processors that maintain state across invocations
27
+ * **Adaptive transformers** - Transformers that can be trained via ``partial_fit``
28
+ * **Composite processors** - Chain multiple processors together efficiently
29
+
30
+ All base classes support both synchronous and asynchronous operation, making them suitable for offline analysis and real-time streaming applications.
35
31
 
36
32
  ## Usage
37
33
 
@@ -88,6 +84,7 @@ We use [`uv`](https://docs.astral.sh/uv/getting-started/installation/) for devel
88
84
  2. Clone and cd into the repository
89
85
  3. Run `uv sync` to create a `.venv` and install dependencies
90
86
  4. Run `uv run pytest tests` to run tests
87
+ 5. (Optional) Install pre-commit hooks: `uv run pre-commit install`
91
88
 
92
89
  ## License
93
90
 
@@ -6,12 +6,13 @@ The `ezmsg.baseproc` module contains the base classes for message processors. Th
6
6
 
7
7
  ### Generic TypeVars
8
8
 
9
- | Idx | Class | Description |
10
- |-----|-----------------------|----------------------------------------------------------------------------|
11
- | 1 | `MessageInType` (Mi) | for messages passed to a consumer, processor, or transformer |
12
- | 2 | `MessageOutType` (Mo) | for messages returned by a producer, processor, or transformer |
13
- | 3 | `SettingsType` | bound to ez.Settings |
14
- | 4 | `StateType` (St) | bound to ProcessorState which is simply ez.State with a `hash: int` field. |
9
+ | Idx | Class | Description |
10
+ |-----|----------------------------|----------------------------------------------------------------------------|
11
+ | 1 | `MessageInType` (Mi) | for messages passed to a consumer, processor, or transformer |
12
+ | 2 | `MessageOutType` (Mo) | for messages returned by a producer, processor, or transformer |
13
+ | 3 | `SettingsType` | bound to ez.Settings |
14
+ | 4 | `StateType` (St) | bound to ProcessorState which is simply ez.State with a `hash: int` field. |
15
+ | 5 | `ClockDrivenSettingsType` | bound to `ClockDrivenSettings` (provides `fs` and `n_time`) |
15
16
 
16
17
 
17
18
  ### Protocols
@@ -47,6 +48,7 @@ Note: `__call__` and `partial_fit` both have asynchronous alternatives: `__acall
47
48
  | 10 | `BaseAsyncTransformer` | 8 | 8 | `__acall__` wraps abstract `_aprocess`; `__call__` runs `__acall__`. |
48
49
  | 11 | `CompositeProcessor` | 1 | 5 | Methods iterate over sequence of processors created in `_initialize_processors`. |
49
50
  | 12 | `CompositeProducer` | 2 | 6 | Similar to `CompositeProcessor`, but first processor must be a producer. |
51
+ | 13 | `BaseClockDrivenProducer` | 5 | 8 | Clock-driven data generator. Implements `_produce(n_samples, time_axis)`. |
50
52
 
51
53
  NOTES:
52
54
  1. Producers do not inherit from `BaseProcessor`, so concrete implementations should subclass `BaseProducer` or `BaseStatefulProducer`.
@@ -60,25 +62,27 @@ do not inherit from `BaseStatefulProcessor` and `BaseStatefulProducer`. They acc
60
62
 
61
63
  ### Generic TypeVars for ezmsg Units
62
64
 
63
- | Idx | Class | Description |
64
- |-----|---------------------------|------------------------------------------------------------------------------------------------------------------|
65
- | 5 | `ProducerType` | bound to `BaseProducer` (hence, also `BaseStatefulProducer`, `CompositeProducer`) |
66
- | 6 | `ConsumerType` | bound to `BaseConsumer`, `BaseStatefulConsumer` |
67
- | 7 | `TransformerType` | bound to `BaseTransformer`, `BaseStatefulTransformer`, `CompositeProcessor` (hence, also `BaseAsyncTransformer`) |
68
- | 8 | `AdaptiveTransformerType` | bound to `BaseAdaptiveTransformer` |
65
+ | Idx | Class | Description |
66
+ |-----|----------------------------|------------------------------------------------------------------------------------------------------------------|
67
+ | 5 | `ProducerType` | bound to `BaseProducer` (hence, also `BaseStatefulProducer`, `CompositeProducer`) |
68
+ | 6 | `ConsumerType` | bound to `BaseConsumer`, `BaseStatefulConsumer` |
69
+ | 7 | `TransformerType` | bound to `BaseTransformer`, `BaseStatefulTransformer`, `CompositeProcessor` (hence, also `BaseAsyncTransformer`) |
70
+ | 8 | `AdaptiveTransformerType` | bound to `BaseAdaptiveTransformer` |
71
+ | 9 | `ClockDrivenProducerType` | bound to `BaseClockDrivenProducer` |
69
72
 
70
73
 
71
74
  ### Abstract implementations (Base Classes) for ezmsg Units using processors:
72
75
 
73
- | Idx | Class | Parents | Expected TypeVars |
74
- |-----|-------------------------------|---------|---------------------------|
75
- | 1 | `BaseProcessorUnit` | - | - |
76
- | 2 | `BaseProducerUnit` | - | `ProducerType` |
77
- | 3 | `BaseConsumerUnit` | 1 | `ConsumerType` |
78
- | 4 | `BaseTransformerUnit` | 1 | `TransformerType` |
79
- | 5 | `BaseAdaptiveTransformerUnit` | 1 | `AdaptiveTransformerType` |
76
+ | Idx | Class | Parents | Expected TypeVars |
77
+ |-----|--------------------------------|---------|----------------------------|
78
+ | 1 | `BaseProcessorUnit` | - | - |
79
+ | 2 | `BaseProducerUnit` | - | `ProducerType` |
80
+ | 3 | `BaseConsumerUnit` | 1 | `ConsumerType` |
81
+ | 4 | `BaseTransformerUnit` | 1 | `TransformerType` |
82
+ | 5 | `BaseAdaptiveTransformerUnit` | 1 | `AdaptiveTransformerType` |
83
+ | 6 | `BaseClockDrivenProducerUnit` | 1 | `ClockDrivenProducerType` |
80
84
 
81
- Note, it is strongly recommended to use `BaseConsumerUnit`, `BaseTransformerUnit`, or `BaseAdaptiveTransformerUnit` for implementing concrete subclasses rather than `BaseProcessorUnit`.
85
+ Note, it is strongly recommended to use `BaseConsumerUnit`, `BaseTransformerUnit`, `BaseAdaptiveTransformerUnit`, or `BaseClockDrivenProducerUnit` for implementing concrete subclasses rather than `BaseProcessorUnit`.
82
86
 
83
87
 
84
88
  ## Implementing a custom standalone processor
@@ -125,6 +129,7 @@ flowchart TD
125
129
  * For stateful processors that need to respond to a change in the incoming data, implement `_hash_message`.
126
130
  * For adaptive transformers, implement `partial_fit`.
127
131
  * For chains of processors (`CompositeProcessor`/ `CompositeProducer`), need to implement `_initialize_processors`.
132
+ * For clock-driven producers (`BaseClockDrivenProducer`), implement `_reset_state(time_axis)` and `_produce(n_samples, time_axis)`. See the [clock-driven how-to guide](how-tos/processors/clockdriven.rst).
128
133
  * See processors in `ezmsg.sigproc` for signal processing examples, or `ezmsg.learn` for machine learning examples.
129
134
  5. Override non-abstract methods if you need special behaviour.
130
135
 
@@ -0,0 +1,224 @@
1
+ How to implement a clock-driven producer?
2
+ #########################################
3
+
4
+ Clock-driven producers generate data synchronized to clock ticks. They are useful
5
+ for signal generators, simulators, and other components that need to produce
6
+ timed data streams.
7
+
8
+ The ``BaseClockDrivenProducer`` base class simplifies this pattern by handling
9
+ all the timing and sample counting logic internally. You only need to implement
10
+ the data generation.
11
+
12
+ When to use BaseClockDrivenProducer
13
+ ===================================
14
+
15
+ Use ``BaseClockDrivenProducer`` when you need to:
16
+
17
+ - Generate synthetic signals (sine waves, noise, test patterns)
18
+ - Simulate sensor data at a specific sample rate
19
+ - Produce timed data streams driven by a ``Clock``
20
+
21
+ This base class eliminates the need for the ``Clock → Counter → Generator``
22
+ pattern by combining the counter functionality into the generator.
23
+
24
+ Basic Structure
25
+ ===============
26
+
27
+ A clock-driven producer consists of three parts:
28
+
29
+ 1. **Settings** - Extends ``ClockDrivenSettings`` (which provides ``fs`` and ``n_time``)
30
+ 2. **State** - Extends ``ClockDrivenState`` (which provides ``counter`` and ``fractional_samples``)
31
+ 3. **Producer** - Extends ``BaseClockDrivenProducer`` and implements ``_reset_state`` and ``_produce``
32
+
33
+ Example: Sine Wave Generator
34
+ ============================
35
+
36
+ Here's a complete example of a sine wave generator:
37
+
38
+ .. code-block:: python
39
+
40
+ import numpy as np
41
+ from ezmsg.util.messages.axisarray import AxisArray, LinearAxis
42
+
43
+ from ezmsg.baseproc import (
44
+ BaseClockDrivenProducer,
45
+ BaseClockDrivenProducerUnit,
46
+ ClockDrivenSettings,
47
+ ClockDrivenState,
48
+ processor_state,
49
+ )
50
+
51
+
52
+ class SinGeneratorSettings(ClockDrivenSettings):
53
+ """
54
+ Settings for the sine wave generator.
55
+
56
+ Inherits from ClockDrivenSettings which provides:
57
+ - fs: Output sampling rate in Hz
58
+ - n_time: Samples per block (optional, derived from clock if None)
59
+ """
60
+
61
+ freq: float = 1.0
62
+ """Frequency of the sine wave in Hz."""
63
+
64
+ amp: float = 1.0
65
+ """Amplitude of the sine wave."""
66
+
67
+ phase: float = 0.0
68
+ """Initial phase in radians."""
69
+
70
+
71
+ @processor_state
72
+ class SinGeneratorState(ClockDrivenState):
73
+ """
74
+ State for the sine wave generator.
75
+
76
+ Inherits from ClockDrivenState which provides:
77
+ - counter: Current sample counter (total samples produced)
78
+ - fractional_samples: For accumulating sub-sample timing
79
+ """
80
+
81
+ ang_freq: float = 0.0
82
+ """Pre-computed angular frequency (2 * pi * freq)."""
83
+
84
+
85
+ class SinGenerator(
86
+ BaseClockDrivenProducer[SinGeneratorSettings, SinGeneratorState]
87
+ ):
88
+ """
89
+ Generates sine wave data synchronized to clock ticks.
90
+ """
91
+
92
+ def _reset_state(self, time_axis: LinearAxis) -> None:
93
+ """
94
+ Initialize state. Called once before first production.
95
+
96
+ Use this to pre-compute values that don't change between chunks.
97
+ """
98
+ self._state.ang_freq = 2 * np.pi * self.settings.freq
99
+
100
+ def _produce(self, n_samples: int, time_axis: LinearAxis) -> AxisArray:
101
+ """
102
+ Generate sine wave data for this chunk.
103
+
104
+ Args:
105
+ n_samples: Number of samples to generate
106
+ time_axis: LinearAxis with correct offset and gain (1/fs)
107
+
108
+ Returns:
109
+ AxisArray containing the sine wave data
110
+ """
111
+ # Calculate time values using the internal counter
112
+ t = (np.arange(n_samples) + self._state.counter) * time_axis.gain
113
+
114
+ # Generate sine wave
115
+ data = self.settings.amp * np.sin(
116
+ self._state.ang_freq * t + self.settings.phase
117
+ )
118
+
119
+ return AxisArray(
120
+ data=data,
121
+ dims=["time"],
122
+ axes={"time": time_axis},
123
+ )
124
+
125
+
126
+ class SinGeneratorUnit(
127
+ BaseClockDrivenProducerUnit[SinGeneratorSettings, SinGenerator]
128
+ ):
129
+ """
130
+ ezmsg Unit wrapper for SinGenerator.
131
+
132
+ Receives clock ticks on INPUT_CLOCK and outputs AxisArray on OUTPUT_SIGNAL.
133
+ """
134
+
135
+ SETTINGS = SinGeneratorSettings
136
+
137
+
138
+ Key Points
139
+ ==========
140
+
141
+ **Settings inheritance**: Your settings class should extend ``ClockDrivenSettings``,
142
+ which provides:
143
+
144
+ - ``fs``: The output sampling rate in Hz
145
+ - ``n_time``: Optional fixed chunk size. If ``None``, chunk size is derived from
146
+ the clock's gain (``fs * clock.gain``)
147
+
148
+ **State inheritance**: Your state class should extend ``ClockDrivenState``,
149
+ which provides:
150
+
151
+ - ``counter``: Tracks total samples produced (use this for continuous signals)
152
+ - ``fractional_samples``: Accumulates sub-sample timing for accurate chunk sizes
153
+
154
+ **The _produce method**: This is where you generate data. You receive:
155
+
156
+ - ``n_samples``: How many samples to generate this chunk
157
+ - ``time_axis``: A ``LinearAxis`` with the correct ``offset`` and ``gain`` (1/fs)
158
+
159
+ The base class automatically:
160
+
161
+ - Computes ``n_samples`` from clock timing or settings
162
+ - Manages the sample counter (incremented after ``_produce`` returns)
163
+ - Handles fractional sample accumulation for non-integer chunk sizes
164
+ - Supports both fixed ``n_time`` and variable chunk modes
165
+
166
+ Using Standalone (Outside ezmsg)
167
+ ================================
168
+
169
+ Clock-driven producers can be used standalone for testing or offline processing:
170
+
171
+ .. code-block:: python
172
+
173
+ from ezmsg.util.messages.axisarray import AxisArray
174
+
175
+ # Create the producer
176
+ producer = SinGenerator(SinGeneratorSettings(
177
+ fs=1000.0, # 1000 Hz sample rate
178
+ n_time=100, # 100 samples per chunk
179
+ freq=10.0, # 10 Hz sine wave
180
+ amp=1.0,
181
+ ))
182
+
183
+ # Simulate clock ticks (LinearAxis with gain=1/dispatch_rate, offset=timestamp)
184
+ clock_tick = AxisArray.LinearAxis(gain=0.1, offset=0.0) # 10 Hz dispatch
185
+
186
+ # Generate data
187
+ result = producer(clock_tick)
188
+ print(f"Shape: {result.data.shape}") # (100,)
189
+ print(f"Sample rate: {1/result.axes['time'].gain} Hz") # 1000.0 Hz
190
+
191
+
192
+ Using with ezmsg
193
+ ================
194
+
195
+ In an ezmsg pipeline, connect a ``Clock`` to your generator's ``INPUT_CLOCK``:
196
+
197
+ .. code-block:: python
198
+
199
+ import ezmsg.core as ez
200
+ from ezmsg.baseproc import Clock, ClockSettings
201
+
202
+
203
+ class SinPipeline(ez.Collection):
204
+ SETTINGS = SinGeneratorSettings
205
+
206
+ CLOCK = Clock()
207
+ GENERATOR = SinGeneratorUnit()
208
+
209
+ def configure(self) -> None:
210
+ self.CLOCK.apply_settings(ClockSettings(dispatch_rate=10.0))
211
+ self.GENERATOR.apply_settings(self.SETTINGS)
212
+
213
+ def network(self) -> ez.NetworkDefinition:
214
+ return (
215
+ (self.CLOCK.OUTPUT_SIGNAL, self.GENERATOR.INPUT_CLOCK),
216
+ )
217
+
218
+
219
+ See Also
220
+ ========
221
+
222
+ - :doc:`API Reference for clockdriven module <../../../api/generated/ezmsg.baseproc.clockdriven>`
223
+ - :doc:`stateful` - For general stateful processor patterns
224
+ - :doc:`unit` - For converting processors to ezmsg Units
@@ -10,4 +10,5 @@ Processor HOW TOs
10
10
  adaptive
11
11
  composite
12
12
  unit
13
+ clockdriven
13
14
  checkpoint
@@ -0,0 +1,18 @@
1
+ ```{include} ../../README.md
2
+ ```
3
+
4
+ ## Documentation
5
+
6
+ ```{toctree}
7
+ :maxdepth: 2
8
+ :caption: Contents:
9
+
10
+ guides/ProcessorsBase
11
+ guides/how-tos/processors/content-processors
12
+ api/index
13
+ ```
14
+
15
+ ## Indices and tables
16
+
17
+ - {ref}`genindex`
18
+ - {ref}`modindex`
@@ -7,6 +7,22 @@ signal processing pipelines in ezmsg.
7
7
 
8
8
  from .__version__ import __version__ as __version__
9
9
 
10
+ # Clock and Counter
11
+ from .clock import (
12
+ Clock,
13
+ ClockProducer,
14
+ ClockSettings,
15
+ ClockState,
16
+ )
17
+
18
+ # Clock-driven producers
19
+ from .clockdriven import (
20
+ BaseClockDrivenProducer,
21
+ ClockDrivenSettings,
22
+ ClockDrivenSettingsType,
23
+ ClockDrivenState,
24
+ )
25
+
10
26
  # Composite processor classes
11
27
  from .composite import (
12
28
  CompositeProcessor,
@@ -14,6 +30,12 @@ from .composite import (
14
30
  CompositeStateful,
15
31
  _get_processor_message_type,
16
32
  )
33
+ from .counter import (
34
+ Counter,
35
+ CounterSettings,
36
+ CounterTransformer,
37
+ CounterTransformerState,
38
+ )
17
39
 
18
40
  # Base processor classes (non-stateful)
19
41
  from .processor import (
@@ -60,15 +82,18 @@ from .stateful import (
60
82
  from .units import (
61
83
  AdaptiveTransformerType,
62
84
  BaseAdaptiveTransformerUnit,
85
+ BaseClockDrivenProducerUnit,
63
86
  BaseConsumerUnit,
64
87
  BaseProcessorUnit,
65
88
  BaseProducerUnit,
66
89
  BaseTransformerUnit,
90
+ ClockDrivenProducerType,
67
91
  ConsumerType,
68
92
  GenAxisArray,
69
93
  ProducerType,
70
94
  TransformerType,
71
95
  get_base_adaptive_transformer_type,
96
+ get_base_clockdriven_producer_type,
72
97
  get_base_consumer_type,
73
98
  get_base_producer_type,
74
99
  get_base_transformer_type,
@@ -102,6 +127,7 @@ __all__ = [
102
127
  "ConsumerType",
103
128
  "TransformerType",
104
129
  "AdaptiveTransformerType",
130
+ "ClockDrivenProducerType",
105
131
  # Decorators
106
132
  "processor_state",
107
133
  # Base processor classes
@@ -117,6 +143,11 @@ __all__ = [
117
143
  "BaseStatefulTransformer",
118
144
  "BaseAdaptiveTransformer",
119
145
  "BaseAsyncTransformer",
146
+ # Clock-driven producers
147
+ "BaseClockDrivenProducer",
148
+ "ClockDrivenSettings",
149
+ "ClockDrivenSettingsType",
150
+ "ClockDrivenState",
120
151
  # Composite classes
121
152
  "CompositeStateful",
122
153
  "CompositeProcessor",
@@ -127,12 +158,14 @@ __all__ = [
127
158
  "BaseConsumerUnit",
128
159
  "BaseTransformerUnit",
129
160
  "BaseAdaptiveTransformerUnit",
161
+ "BaseClockDrivenProducerUnit",
130
162
  "GenAxisArray",
131
163
  # Type resolution helpers
132
164
  "get_base_producer_type",
133
165
  "get_base_consumer_type",
134
166
  "get_base_transformer_type",
135
167
  "get_base_adaptive_transformer_type",
168
+ "get_base_clockdriven_producer_type",
136
169
  "_get_base_processor_settings_type",
137
170
  "_get_base_processor_message_in_type",
138
171
  "_get_base_processor_message_out_type",
@@ -152,4 +185,13 @@ __all__ = [
152
185
  # Type utilities
153
186
  "check_message_type_compatibility",
154
187
  "resolve_typevar",
188
+ # Clock and Counter
189
+ "Clock",
190
+ "ClockProducer",
191
+ "ClockSettings",
192
+ "ClockState",
193
+ "Counter",
194
+ "CounterSettings",
195
+ "CounterTransformer",
196
+ "CounterTransformerState",
155
197
  ]
@@ -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 = '1.0.3'
32
- __version_tuple__ = version_tuple = (1, 0, 3)
31
+ __version__ = version = '1.2.0'
32
+ __version_tuple__ = version_tuple = (1, 2, 0)
33
33
 
34
34
  __commit_id__ = commit_id = None