smoothiepy 0.0.1__py3-none-any.whl → 0.1.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.
- smoothiepy/__init__.py +0 -1
- smoothiepy/core.py +32 -0
- smoothiepy/filter/__init__.py +0 -0
- smoothiepy/filter/basefilter.py +122 -0
- smoothiepy/filter/filter1d.py +324 -0
- smoothiepy/filter/filter2d.py +41 -0
- smoothiepy/filter/filter2d_naive.py +266 -0
- smoothiepy/smoother/__init__.py +0 -0
- smoothiepy/smoother/builder.py +110 -0
- smoothiepy/smoother/smoother.py +200 -0
- smoothiepy-0.1.0.dist-info/METADATA +181 -0
- smoothiepy-0.1.0.dist-info/RECORD +15 -0
- {smoothiepy-0.0.1.dist-info → smoothiepy-0.1.0.dist-info}/WHEEL +1 -1
- smoothiepy-0.1.0.dist-info/entry_points.txt +4 -0
- smoothiepy-0.1.0.dist-info/licenses/LICENSE +674 -0
- smoothiepy/easing_functions.py +0 -238
- smoothiepy-0.0.1.dist-info/LICENSE +0 -21
- smoothiepy-0.0.1.dist-info/METADATA +0 -16
- smoothiepy-0.0.1.dist-info/RECORD +0 -6
@@ -0,0 +1,266 @@
|
|
1
|
+
"""
|
2
|
+
Contains the two-dimensional naive filter implementation using
|
3
|
+
two 1D filters in x and y directions.
|
4
|
+
"""
|
5
|
+
from abc import ABC
|
6
|
+
import numpy as np
|
7
|
+
|
8
|
+
from smoothiepy.filter.basefilter import Filter2D, Filter1D, MovingAverageType
|
9
|
+
from smoothiepy.filter.filter1d import (
|
10
|
+
SimpleMovingAverageFilter1D, WeightedMovingAverageFilter1D,
|
11
|
+
GaussianAverageFilter1D, MedianAverageFilter1D,
|
12
|
+
ExponentialMovingAverageFilter1D, CumulativeMovingAverageFilter1D,
|
13
|
+
FixationSmoothFilter1D, MultiPassMovingAverage1D
|
14
|
+
)
|
15
|
+
|
16
|
+
|
17
|
+
class NaiveFilter2D(Filter2D, ABC):
|
18
|
+
"""
|
19
|
+
Provides a basic 2D filtering mechanism, where input data is processed
|
20
|
+
through two 1D filters (`filter_x` and `filter_y`). It is intended to serve as
|
21
|
+
a straightforward 2D filtering implementation that deals with basic
|
22
|
+
use cases of filtering in two dimensions.
|
23
|
+
|
24
|
+
:ivar filter_x: A 1D filter is applied on the x-buffer data.
|
25
|
+
:type filter_x: Filter1D | None
|
26
|
+
:ivar filter_y: A 1D filter is applied on the y-buffer data.
|
27
|
+
:type filter_y: Filter1D | None
|
28
|
+
"""
|
29
|
+
def __init__(self):
|
30
|
+
super().__init__(window_size_x=1, window_size_y=1)
|
31
|
+
self.filter_x: Filter1D | None = None
|
32
|
+
self.filter_y: Filter1D | None = None
|
33
|
+
|
34
|
+
def _process_next(self, buffer_x: np.array, buffer_y: np.array) \
|
35
|
+
-> tuple[float | int, float | int]:
|
36
|
+
avg_x = self.filter_x.next(buffer_x[0])
|
37
|
+
avg_y = self.filter_y.next(buffer_y[0])
|
38
|
+
return avg_x, avg_y
|
39
|
+
|
40
|
+
|
41
|
+
class NaiveSimpleMovingAverageFilter2D(NaiveFilter2D):
|
42
|
+
"""
|
43
|
+
The NaiveSimpleMovingAverageFilter2D class implements a 2D simple moving
|
44
|
+
average filter. It smooths sequential data points along both x and y
|
45
|
+
axes using separate 1D simple moving average filters.
|
46
|
+
|
47
|
+
:param window_size: The size of the moving average window for the x-axis.
|
48
|
+
Must be a positive integer.
|
49
|
+
If the y-axis window size is not provided, the
|
50
|
+
x-axis window size will be used for both axes.
|
51
|
+
:type window_size: int
|
52
|
+
:param window_size_y: The size of the moving average window for the y-axis.
|
53
|
+
Must be a positive integer.
|
54
|
+
If not provided, it defaults to the x-axis window size.
|
55
|
+
:type window_size_y: int
|
56
|
+
"""
|
57
|
+
def __init__(self, window_size, window_size_y=None):
|
58
|
+
if window_size_y is None:
|
59
|
+
window_size_y = window_size
|
60
|
+
super().__init__()
|
61
|
+
self.filter_x = SimpleMovingAverageFilter1D(window_size=window_size)
|
62
|
+
self.filter_y = SimpleMovingAverageFilter1D(window_size=window_size_y)
|
63
|
+
|
64
|
+
|
65
|
+
class NaiveWeightedMovingAverageFilter2D(NaiveFilter2D):
|
66
|
+
"""
|
67
|
+
A 2D filter that computes a weighted average of the input data over a specified window size
|
68
|
+
in both x and y directions. The weights are linearly decreasing from 1 to 0, applied to the
|
69
|
+
most recent data points.
|
70
|
+
|
71
|
+
:param window_size: The size of the weighted moving average window for the x-axis.
|
72
|
+
Must be a positive integer.
|
73
|
+
If the y-axis window size is not provided, the
|
74
|
+
x-axis window size will be used for both axes.
|
75
|
+
:type window_size: int
|
76
|
+
:param window_size_y: The size of the weighted moving average window for the y-axis.
|
77
|
+
:type window_size_y: int
|
78
|
+
"""
|
79
|
+
def __init__(self, window_size: int, window_size_y: int = None):
|
80
|
+
if window_size_y is None:
|
81
|
+
window_size_y = window_size
|
82
|
+
super().__init__()
|
83
|
+
self.filter_x = WeightedMovingAverageFilter1D(window_size=window_size)
|
84
|
+
self.filter_y = WeightedMovingAverageFilter1D(window_size=window_size_y)
|
85
|
+
|
86
|
+
|
87
|
+
class NaiveGaussianAverageFilter2D(NaiveFilter2D):
|
88
|
+
"""
|
89
|
+
A 2D filter that implements a Gaussian Average Filter for two-dimensional data.
|
90
|
+
It applies a Gaussian weighting function over
|
91
|
+
a sliding window of data in both x and y directions.
|
92
|
+
|
93
|
+
:param window_size: The size of the Gaussian window for the x-axis.
|
94
|
+
Must be a positive integer.
|
95
|
+
If the y-axis window size is not provided, the
|
96
|
+
x-axis window size will be used for both axes.
|
97
|
+
:type window_size: int
|
98
|
+
:param window_size_y: The size of the Gaussian window for the y-axis.
|
99
|
+
Must be a positive integer.
|
100
|
+
If not provided, it defaults to the x-axis window size.
|
101
|
+
:type window_size_y: int
|
102
|
+
:param std_dev_x: The standard deviation of the Gaussian distribution for the x-axis.
|
103
|
+
Must be a positive value. If not provided, it defaults to one-third of the window size.
|
104
|
+
:type std_dev_x: float
|
105
|
+
:param std_dev_y: The standard deviation of the Gaussian distribution for the y-axis.
|
106
|
+
Must be a positive value. If not provided, it defaults to one-third of the window size_y.
|
107
|
+
:type std_dev_y: float
|
108
|
+
"""
|
109
|
+
def __init__(self, window_size: int, window_size_y: int = None,
|
110
|
+
std_dev_x: float = None, std_dev_y: float = None):
|
111
|
+
if window_size_y is None:
|
112
|
+
window_size_y = window_size
|
113
|
+
super().__init__()
|
114
|
+
self.filter_x = GaussianAverageFilter1D(window_size=window_size, std_dev=std_dev_x)
|
115
|
+
self.filter_y = GaussianAverageFilter1D(window_size=window_size_y, std_dev=std_dev_y)
|
116
|
+
|
117
|
+
|
118
|
+
class NaiveMedianAverageFilter2D(NaiveFilter2D):
|
119
|
+
"""
|
120
|
+
A 2D filter that computes the median of the input data over a specified
|
121
|
+
window size in both x and y directions.
|
122
|
+
|
123
|
+
:param window_size: The size of the median window for the x-axis.
|
124
|
+
Must be a positive integer.
|
125
|
+
If the y-axis window size is not provided, the
|
126
|
+
x-axis window size will be used for both axes.
|
127
|
+
:type window_size: int
|
128
|
+
:param window_size_y: The size of the median window for the y-axis.
|
129
|
+
Must be a positive integer.
|
130
|
+
If not provided, it defaults to the x-axis window size.
|
131
|
+
:type window_size_y: int
|
132
|
+
"""
|
133
|
+
def __init__(self, window_size: int, window_size_y: int = None):
|
134
|
+
if window_size_y is None:
|
135
|
+
window_size_y = window_size
|
136
|
+
super().__init__()
|
137
|
+
self.filter_x = MedianAverageFilter1D(window_size=window_size)
|
138
|
+
self.filter_y = MedianAverageFilter1D(window_size=window_size_y)
|
139
|
+
|
140
|
+
|
141
|
+
class NaiveExponentialMovingAverageFilter2D(NaiveFilter2D):
|
142
|
+
"""
|
143
|
+
A 2D filter that implements an exponential moving average filter for two-dimensional data.
|
144
|
+
It applies exponential moving average weights to the current and
|
145
|
+
the previous filtered data points in both x and y directions.
|
146
|
+
|
147
|
+
:param alpha: The smoothing factor for the x-axis. Must be between 0 and 1 (inclusive).
|
148
|
+
If `alpha_y` is not provided, it will be set to the same value as `alpha`.
|
149
|
+
:type alpha: float
|
150
|
+
:param alpha_y: The smoothing factor for the y-axis. Must be between 0 and 1 (inclusive).
|
151
|
+
If not provided, it defaults to the x-axis alpha value.
|
152
|
+
:type alpha_y: float
|
153
|
+
"""
|
154
|
+
def __init__(self, alpha: float, alpha_y: float = None):
|
155
|
+
if alpha_y is None:
|
156
|
+
alpha_y = alpha
|
157
|
+
super().__init__()
|
158
|
+
self.filter_x = ExponentialMovingAverageFilter1D(alpha=alpha)
|
159
|
+
self.filter_y = ExponentialMovingAverageFilter1D(alpha=alpha_y)
|
160
|
+
|
161
|
+
|
162
|
+
class NaiveCumulativeMovingAverageFilter2D(NaiveFilter2D):
|
163
|
+
"""
|
164
|
+
A 2D filter that implements a cumulative moving average filter for two-dimensional data.
|
165
|
+
It computes the cumulative average of the input data points as they are processed,
|
166
|
+
updating the average with each new data point in both x and y directions.
|
167
|
+
"""
|
168
|
+
def __init__(self):
|
169
|
+
super().__init__()
|
170
|
+
self.filter_x = CumulativeMovingAverageFilter1D()
|
171
|
+
self.filter_y = CumulativeMovingAverageFilter1D()
|
172
|
+
|
173
|
+
|
174
|
+
class NaiveFixationSmoothFilter2D(NaiveFilter2D):
|
175
|
+
"""
|
176
|
+
A 2D filter that implements a fixation smooth filter for two-dimensional data.
|
177
|
+
It uses a weighted averaging mechanism in conjunction with
|
178
|
+
standard deviation-based thresholding to determine whether to maintain
|
179
|
+
or update the fixation value in both x and y directions.
|
180
|
+
|
181
|
+
An example for the threshold would be calculated using the following formula:
|
182
|
+
``{screen_width_px} * 0.004 + sqrt({window_size})``.
|
183
|
+
Where `screen_width_px` is the width of the screen in pixels and
|
184
|
+
`window_size` is the size of the sliding window used for the filter.
|
185
|
+
This could be used for eye-tracking data to smooth out noise when you fixate on a point
|
186
|
+
for a longer period of time.
|
187
|
+
|
188
|
+
:param window_size: The size of the sliding window for the x-axis.
|
189
|
+
Must be a positive integer.
|
190
|
+
If the y-axis window size is not provided, it will be set to the
|
191
|
+
same value as `window_size`.
|
192
|
+
:type window_size: int
|
193
|
+
:param window_size_y: The size of the sliding window for the y-axis.
|
194
|
+
Must be a positive integer.
|
195
|
+
If not provided, it defaults to the x-axis window size.
|
196
|
+
:type window_size_y: int
|
197
|
+
:param threshold: The threshold value for the x-axis.
|
198
|
+
:type threshold: float
|
199
|
+
:param threshold_y: The threshold value for the y-axis.
|
200
|
+
:type threshold_y: float
|
201
|
+
"""
|
202
|
+
def __init__(self, window_size: int, threshold: float,
|
203
|
+
window_size_y: int = None, threshold_y: float = None):
|
204
|
+
if window_size_y is None:
|
205
|
+
window_size_y = window_size
|
206
|
+
if threshold_y is None:
|
207
|
+
threshold_y = threshold
|
208
|
+
super().__init__()
|
209
|
+
self.filter_x = FixationSmoothFilter1D(window_size=window_size, threshold=threshold)
|
210
|
+
self.filter_y = FixationSmoothFilter1D(window_size=window_size_y, threshold=threshold_y)
|
211
|
+
|
212
|
+
|
213
|
+
class NaiveMultiPassMovingAverage2D(NaiveFilter2D):
|
214
|
+
"""
|
215
|
+
A 2D filter that implements a multi-pass moving average filter for two-dimensional data.
|
216
|
+
It applies a user-defined number of passes over the data using the
|
217
|
+
specified moving average filter type in both x and y directions.
|
218
|
+
|
219
|
+
:param window_size: The size of the sliding window for the x-axis.
|
220
|
+
Must be a positive integer.
|
221
|
+
If the y-axis window size is not provided, it will be set to the
|
222
|
+
same value as `window_size`.
|
223
|
+
:type window_size: int
|
224
|
+
:param window_size_y: The size of the sliding window for the y-axis.
|
225
|
+
Must be a positive integer.
|
226
|
+
If not provided, it defaults to the x-axis window size.
|
227
|
+
:type window_size_y: int
|
228
|
+
:param num_passes: Number of passes to apply to the moving average filter for the x-axis.
|
229
|
+
Must be a positive integer.
|
230
|
+
If `num_passes_y` is not provided, it will be set to the same value as `num_passes`.
|
231
|
+
:type num_passes: int
|
232
|
+
:param num_passes_y: Number of passes to apply to the moving average filter for the y-axis.
|
233
|
+
Must be a positive integer.
|
234
|
+
If not provided, it defaults to the x-axis number of passes.
|
235
|
+
:type num_passes_y: int
|
236
|
+
:param average_filter_type_x: The type of moving average filter to use for the x-axis.
|
237
|
+
Defaults to ``MovingAverageType.SIMPLE``.
|
238
|
+
If `average_filter_type_y` is not provided, it will be set to the
|
239
|
+
same value as `average_filter_type_x`.
|
240
|
+
:type average_filter_type_x: MovingAverageType
|
241
|
+
:param average_filter_type_y: The type of moving average filter to use for the y-axis.
|
242
|
+
If not provided, it defaults to the x-axis average filter type.
|
243
|
+
:type average_filter_type_y: MovingAverageType
|
244
|
+
"""
|
245
|
+
def __init__(self, window_size: int, num_passes: int,
|
246
|
+
window_size_y: int = None, num_passes_y: int = None,
|
247
|
+
average_filter_type_x: MovingAverageType = MovingAverageType.SIMPLE,
|
248
|
+
average_filter_type_y: MovingAverageType = None):
|
249
|
+
if window_size_y is None:
|
250
|
+
window_size_y = window_size
|
251
|
+
if num_passes_y is None:
|
252
|
+
num_passes_y = num_passes
|
253
|
+
if average_filter_type_y is None:
|
254
|
+
average_filter_type_y = average_filter_type_x
|
255
|
+
|
256
|
+
super().__init__()
|
257
|
+
self.filter_x = MultiPassMovingAverage1D(
|
258
|
+
window_size=window_size,
|
259
|
+
num_passes=num_passes,
|
260
|
+
average_filter_type=average_filter_type_x
|
261
|
+
)
|
262
|
+
self.filter_y = MultiPassMovingAverage1D(
|
263
|
+
window_size=window_size_y,
|
264
|
+
num_passes=num_passes_y,
|
265
|
+
average_filter_type=average_filter_type_y
|
266
|
+
)
|
File without changes
|
@@ -0,0 +1,110 @@
|
|
1
|
+
"""
|
2
|
+
Contains the helper classes to build a signal smoother.
|
3
|
+
"""
|
4
|
+
from smoothiepy.filter.basefilter import Filter1D, Filter2D
|
5
|
+
from smoothiepy.smoother.smoother import Smoother1DContinuous, Smoother2DContinuous
|
6
|
+
|
7
|
+
|
8
|
+
class SmootherBuilder:
|
9
|
+
"""
|
10
|
+
Provides utilities for building smoother objects for data.
|
11
|
+
|
12
|
+
This class provides methods to construct smoother objects based on
|
13
|
+
specified dimensional requirements. It currently supports
|
14
|
+
one-dimensional smoother creation.
|
15
|
+
"""
|
16
|
+
@staticmethod
|
17
|
+
def one_dimensional() -> 'Smoother1DBuilder':
|
18
|
+
return Smoother1DBuilder()
|
19
|
+
|
20
|
+
@staticmethod
|
21
|
+
def two_dimensional() -> 'Smoother2DBuilder':
|
22
|
+
return Smoother2DBuilder()
|
23
|
+
|
24
|
+
def set_dimensions(self, dimensions: int) -> 'Smoother1DBuilder | Smoother2DBuilder':
|
25
|
+
if dimensions == 1:
|
26
|
+
return self.one_dimensional()
|
27
|
+
if dimensions == 2:
|
28
|
+
return self.two_dimensional()
|
29
|
+
|
30
|
+
raise ValueError("Unsupported dimensions. Currently only 1D and 2D is supported.")
|
31
|
+
|
32
|
+
|
33
|
+
class Smoother1DBuilder:
|
34
|
+
"""
|
35
|
+
Provides a builder for creating 1D signal smoother instances.
|
36
|
+
|
37
|
+
This class offers static methods to initialize builders for smoothing
|
38
|
+
operations tailored to different types of data. It simplifies the
|
39
|
+
creation of signal smoother objects by providing predefined builder
|
40
|
+
methods.
|
41
|
+
"""
|
42
|
+
@staticmethod
|
43
|
+
def continuous() -> 'Smoother1DContinuousBuilder':
|
44
|
+
return Smoother1DContinuousBuilder()
|
45
|
+
|
46
|
+
|
47
|
+
class Smoother2DBuilder:
|
48
|
+
"""
|
49
|
+
Provides a builder for creating 2D signal smoother instances.
|
50
|
+
|
51
|
+
This class offers static methods to initialize builders for smoothing
|
52
|
+
operations tailored to different types of data. It simplifies the
|
53
|
+
creation of signal smoother objects by providing predefined builder
|
54
|
+
methods.
|
55
|
+
"""
|
56
|
+
@staticmethod
|
57
|
+
def set_continuous() -> 'Smoother2DContinuousBuilder':
|
58
|
+
return Smoother2DContinuousBuilder()
|
59
|
+
|
60
|
+
|
61
|
+
class Smoother1DContinuousBuilder:
|
62
|
+
"""
|
63
|
+
A builder class for creating 1D continuous signal smoother.
|
64
|
+
|
65
|
+
This class facilitates the creation and configuration of a 1D continuous
|
66
|
+
signal smoother by allowing filters to be attached and then constructing
|
67
|
+
the smoother object.
|
68
|
+
"""
|
69
|
+
def __init__(self):
|
70
|
+
self.__smoother = Smoother1DContinuous()
|
71
|
+
|
72
|
+
def attach_filter(self, filter_obj: Filter1D) -> 'Smoother1DContinuousBuilder':
|
73
|
+
self.__smoother.attach_filter(filter_obj)
|
74
|
+
return self
|
75
|
+
|
76
|
+
def build(self) -> Smoother1DContinuous:
|
77
|
+
self.__smoother.build()
|
78
|
+
return self.__smoother
|
79
|
+
|
80
|
+
|
81
|
+
class Smoother2DContinuousBuilder:
|
82
|
+
"""
|
83
|
+
A builder class for creating 2D continuous signal smoother.
|
84
|
+
|
85
|
+
This class facilitates the creation and configuration of a 2D continuous
|
86
|
+
signal smoother by allowing filters to be attached and then constructing
|
87
|
+
the smoother object.
|
88
|
+
"""
|
89
|
+
def __init__(self):
|
90
|
+
self.__smoother = Smoother2DContinuous()
|
91
|
+
|
92
|
+
def attach_filter(self, filter_obj: Filter2D) -> 'Smoother2DContinuousBuilder':
|
93
|
+
self.__smoother.attach_filter(filter_obj)
|
94
|
+
return self
|
95
|
+
|
96
|
+
def build(self) -> Smoother2DContinuous:
|
97
|
+
self.__smoother.build()
|
98
|
+
return self.__smoother
|
99
|
+
|
100
|
+
|
101
|
+
# class SignalSmootherBuilder1DList:
|
102
|
+
# def __init__(self):
|
103
|
+
# self.smoother = SignalSmootherSeparateLists1D()
|
104
|
+
#
|
105
|
+
# def attach_filter(self, filter_obj: BaseFilter1D):
|
106
|
+
# self.smoother.attach_filter(filter_obj)
|
107
|
+
#
|
108
|
+
# def build(self):
|
109
|
+
# self.smoother.build()
|
110
|
+
# return self.smoother
|
@@ -0,0 +1,200 @@
|
|
1
|
+
"""
|
2
|
+
Contains the Signal Smoother class which is the main class to smooth signals.
|
3
|
+
"""
|
4
|
+
from abc import ABC, abstractmethod
|
5
|
+
from smoothiepy.filter.basefilter import Filter, Filter1D, Filter2D
|
6
|
+
|
7
|
+
|
8
|
+
class Smoother(ABC):
|
9
|
+
"""
|
10
|
+
Represents an abstract base class for smoothing signals by attaching and managing filters.
|
11
|
+
|
12
|
+
This class is designed as a foundation for implementing specific signal smoothing
|
13
|
+
strategies. It provides a structure for managing filters and implementing custom
|
14
|
+
signal smoothing logic.
|
15
|
+
|
16
|
+
:ivar filter_list: A list that holds the filters attached to this smoother.
|
17
|
+
:type filter_list: list[Filter]
|
18
|
+
"""
|
19
|
+
def __init__(self):
|
20
|
+
self.filter_list: list[Filter] = []
|
21
|
+
|
22
|
+
@abstractmethod
|
23
|
+
def attach_filter(self, filter_obj: Filter) -> None:
|
24
|
+
"""
|
25
|
+
Attaches a filter object to the implementing class.
|
26
|
+
|
27
|
+
:param filter_obj: The filter object to attach.
|
28
|
+
:type filter_obj: Filter
|
29
|
+
"""
|
30
|
+
|
31
|
+
@abstractmethod
|
32
|
+
def build(self):
|
33
|
+
"""
|
34
|
+
Builds the final configuration of the smoother, setting up the filters
|
35
|
+
and their parameters as needed.
|
36
|
+
|
37
|
+
:raises NotImplementedError: If the subclass does not implement this method.
|
38
|
+
"""
|
39
|
+
|
40
|
+
|
41
|
+
class Smoother1D(Smoother, ABC):
|
42
|
+
"""
|
43
|
+
Provides one-dimensional signal smoothing functionality.
|
44
|
+
|
45
|
+
This class is an extension of the ``Smoother`` class designed specifically
|
46
|
+
for one-dimensional signal data. It maintains a list of 1D filters and allows
|
47
|
+
attachment of additional filters which must be of type Filter1D.
|
48
|
+
|
49
|
+
:ivar filter_list: Stores instances of Filter1D for smoothing operations.
|
50
|
+
:type filter_list: list[Filter1D]
|
51
|
+
"""
|
52
|
+
def __init__(self):
|
53
|
+
super().__init__()
|
54
|
+
self.filter_list: list[Filter1D] = []
|
55
|
+
|
56
|
+
def attach_filter(self, filter_obj: Filter) -> None:
|
57
|
+
if not isinstance(filter_obj, Filter1D):
|
58
|
+
raise TypeError("filter_obj must be an 1D filter")
|
59
|
+
|
60
|
+
self.filter_list.append(filter_obj)
|
61
|
+
|
62
|
+
|
63
|
+
class Smoother1DContinuous(Smoother1D):
|
64
|
+
"""
|
65
|
+
A class for continuously smoothing one-dimensional data.
|
66
|
+
|
67
|
+
Provides functionality to smooth incoming data points in a continuous manner
|
68
|
+
using a list of filters.
|
69
|
+
The smoothed value is updated as new data points are added.
|
70
|
+
|
71
|
+
:ivar last_filtered_value: Stores the most recent smoothed value.
|
72
|
+
:type last_filtered_value: float | int
|
73
|
+
"""
|
74
|
+
def __init__(self):
|
75
|
+
super().__init__()
|
76
|
+
self.last_filtered_value: float | int = 0.0
|
77
|
+
|
78
|
+
def build(self):
|
79
|
+
pass
|
80
|
+
# self.filter_list[-1].set_buffer_size(1)
|
81
|
+
# for cur_filter, next_filter in zip(self.filter_list, self.filter_list[1:]):
|
82
|
+
# cur_filter.set_buffer_size(next_filter.window_size)
|
83
|
+
|
84
|
+
def add_and_get(self, data: float | int) -> float | int:
|
85
|
+
"""
|
86
|
+
Adds the given data to the signal smoother and returns the filtered value.
|
87
|
+
|
88
|
+
:param data: The numeric value to be added.
|
89
|
+
:type data: float | int
|
90
|
+
:return: Filtered value after the input has been added.
|
91
|
+
:rtype: float | int
|
92
|
+
"""
|
93
|
+
self.add(data)
|
94
|
+
return self.get()
|
95
|
+
|
96
|
+
def add(self, data: float | int) -> None:
|
97
|
+
"""
|
98
|
+
Adds a new data point to the signal smoother.
|
99
|
+
|
100
|
+
:param data: The data point to be added.
|
101
|
+
:type data: float | int
|
102
|
+
"""
|
103
|
+
temp_filtered_value = data
|
104
|
+
for cur_filter in self.filter_list:
|
105
|
+
temp_filtered_value = cur_filter.next(temp_filtered_value)
|
106
|
+
|
107
|
+
self.last_filtered_value = temp_filtered_value
|
108
|
+
|
109
|
+
def get(self) -> float | int:
|
110
|
+
"""
|
111
|
+
Retrieves the smoothed value from the signal smoother.
|
112
|
+
|
113
|
+
:return: The smoothed value.
|
114
|
+
:rtype: float | int
|
115
|
+
"""
|
116
|
+
return self.last_filtered_value
|
117
|
+
|
118
|
+
|
119
|
+
class Smoother2D(Smoother, ABC):
|
120
|
+
"""
|
121
|
+
Provides two-dimensional signal smoothing functionality.
|
122
|
+
|
123
|
+
This class is an extension of the ``Smoother`` class designed specifically
|
124
|
+
for two-dimensional signal data. It maintains a list of 2D filters and allows
|
125
|
+
attachment of additional filters which must be of type Filter2D.
|
126
|
+
|
127
|
+
:ivar filter_list: Stores instances of Filter2D for smoothing operations.
|
128
|
+
:type filter_list: list[Filter2D]
|
129
|
+
"""
|
130
|
+
def __init__(self):
|
131
|
+
super().__init__()
|
132
|
+
self.filter_list: list[Filter2D] = []
|
133
|
+
|
134
|
+
def attach_filter(self, filter_obj: Filter) -> None:
|
135
|
+
if not isinstance(filter_obj, Filter2D):
|
136
|
+
raise TypeError("filter_obj must be an 2D filter")
|
137
|
+
|
138
|
+
self.filter_list.append(filter_obj)
|
139
|
+
|
140
|
+
|
141
|
+
class Smoother2DContinuous(Smoother2D):
|
142
|
+
"""
|
143
|
+
A class for continuously smoothing two-dimensional data.
|
144
|
+
|
145
|
+
Provides functionality to smooth incoming data points in a continuous manner
|
146
|
+
using a list of filters.
|
147
|
+
The smoothed value is updated as new data points are added.
|
148
|
+
|
149
|
+
:ivar last_filtered_value: Stores the most recent smoothed value.
|
150
|
+
:type last_filtered_value: float | int
|
151
|
+
"""
|
152
|
+
def __init__(self):
|
153
|
+
super().__init__()
|
154
|
+
self.last_filtered_value: tuple[float | int, float | int] = (0.0, 0.0)
|
155
|
+
|
156
|
+
def build(self):
|
157
|
+
pass
|
158
|
+
|
159
|
+
def add_and_get(self, data_x: float | int, data_y: float | int) \
|
160
|
+
-> tuple[float | int, float | int]:
|
161
|
+
"""
|
162
|
+
Adds the given data to the signal smoother and returns the filtered value.
|
163
|
+
|
164
|
+
:param data_x: The first numeric value to be added.
|
165
|
+
:type data_x: float | int
|
166
|
+
:param data_y: The second numeric value to be added.
|
167
|
+
:type data_y: float | int
|
168
|
+
:return: Filtered value after the input has been added.
|
169
|
+
:rtype: float | int
|
170
|
+
"""
|
171
|
+
self.add(data_x=data_x, data_y=data_y)
|
172
|
+
return self.get()
|
173
|
+
|
174
|
+
def add(self, data_x: float | int, data_y: float | int) -> None:
|
175
|
+
"""
|
176
|
+
Adds a new data point to the signal smoother.
|
177
|
+
|
178
|
+
:param data_x: The first numeric value to be added.
|
179
|
+
:type data_x: float | int
|
180
|
+
:param data_y: The second numeric value to be added.
|
181
|
+
:type data_y: float | int
|
182
|
+
"""
|
183
|
+
temp_filtered_value = data_x, data_y
|
184
|
+
for cur_filter in self.filter_list:
|
185
|
+
temp_filtered_value = cur_filter.next(temp_filtered_value)
|
186
|
+
|
187
|
+
self.last_filtered_value = temp_filtered_value
|
188
|
+
|
189
|
+
def get(self) -> tuple[float | int, float | int]:
|
190
|
+
"""
|
191
|
+
Retrieves the smoothed value from the signal smoother.
|
192
|
+
|
193
|
+
:return: The smoothed value.
|
194
|
+
:rtype: float | int
|
195
|
+
"""
|
196
|
+
return self.last_filtered_value
|
197
|
+
|
198
|
+
# class SignalSmootherSeparateLists1D:
|
199
|
+
# def filter_list(self, signal: list[float]) -> list[float]:
|
200
|
+
# return signal
|