dspx 0.1.1-alpha.0

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 (172) hide show
  1. package/.github/workflows/ci.yml +185 -0
  2. package/.vscode/c_cpp_properties.json +17 -0
  3. package/.vscode/settings.json +68 -0
  4. package/.vscode/tasks.json +28 -0
  5. package/DISCLAIMER.md +32 -0
  6. package/LICENSE +21 -0
  7. package/README.md +1803 -0
  8. package/ROADMAP.md +192 -0
  9. package/TECHNICAL_DEBT.md +165 -0
  10. package/binding.gyp +65 -0
  11. package/docs/ADVANCED_LOGGER_FEATURES.md +598 -0
  12. package/docs/AUTHENTICATION_SECURITY.md +396 -0
  13. package/docs/BACKEND_IMPROVEMENTS.md +399 -0
  14. package/docs/CHEBYSHEV_BIQUAD_EQ_IMPLEMENTATION.md +405 -0
  15. package/docs/FFT_IMPLEMENTATION.md +490 -0
  16. package/docs/FFT_IMPROVEMENTS_SUMMARY.md +387 -0
  17. package/docs/FFT_USER_GUIDE.md +494 -0
  18. package/docs/FILTERS_IMPLEMENTATION.md +260 -0
  19. package/docs/FILTER_API_GUIDE.md +418 -0
  20. package/docs/FIR_SIMD_OPTIMIZATION.md +175 -0
  21. package/docs/LOGGER_API_REFERENCE.md +350 -0
  22. package/docs/NOTCH_FILTER_QUICK_REF.md +121 -0
  23. package/docs/PHASE2_TESTS_AND_NOTCH_FILTER.md +341 -0
  24. package/docs/PHASES_5_7_SUMMARY.md +403 -0
  25. package/docs/PIPELINE_FILTER_INTEGRATION.md +446 -0
  26. package/docs/SIMD_OPTIMIZATIONS.md +211 -0
  27. package/docs/TEST_MIGRATION_SUMMARY.md +173 -0
  28. package/docs/TIMESERIES_IMPLEMENTATION_SUMMARY.md +322 -0
  29. package/docs/TIMESERIES_QUICK_REF.md +85 -0
  30. package/docs/advanced.md +559 -0
  31. package/docs/time-series-guide.md +617 -0
  32. package/docs/time-series-migration.md +376 -0
  33. package/jest.config.js +37 -0
  34. package/package.json +42 -0
  35. package/prebuilds/linux-x64/dsp-ts-redis.node +0 -0
  36. package/prebuilds/win32-x64/dsp-ts-redis.node +0 -0
  37. package/scripts/test.js +24 -0
  38. package/src/build/dsp-ts-redis.node +0 -0
  39. package/src/native/DspPipeline.cc +675 -0
  40. package/src/native/DspPipeline.h +44 -0
  41. package/src/native/FftBindings.cc +817 -0
  42. package/src/native/FilterBindings.cc +1001 -0
  43. package/src/native/IDspStage.h +53 -0
  44. package/src/native/adapters/InterpolatorStage.h +201 -0
  45. package/src/native/adapters/MeanAbsoluteValueStage.h +289 -0
  46. package/src/native/adapters/MovingAverageStage.h +306 -0
  47. package/src/native/adapters/RectifyStage.h +88 -0
  48. package/src/native/adapters/ResamplerStage.h +238 -0
  49. package/src/native/adapters/RmsStage.h +299 -0
  50. package/src/native/adapters/SscStage.h +121 -0
  51. package/src/native/adapters/VarianceStage.h +307 -0
  52. package/src/native/adapters/WampStage.h +114 -0
  53. package/src/native/adapters/WaveformLengthStage.h +115 -0
  54. package/src/native/adapters/ZScoreNormalizeStage.h +326 -0
  55. package/src/native/core/FftEngine.cc +441 -0
  56. package/src/native/core/FftEngine.h +224 -0
  57. package/src/native/core/FirFilter.cc +324 -0
  58. package/src/native/core/FirFilter.h +149 -0
  59. package/src/native/core/IirFilter.cc +576 -0
  60. package/src/native/core/IirFilter.h +210 -0
  61. package/src/native/core/MovingAbsoluteValueFilter.cc +17 -0
  62. package/src/native/core/MovingAbsoluteValueFilter.h +135 -0
  63. package/src/native/core/MovingAverageFilter.cc +18 -0
  64. package/src/native/core/MovingAverageFilter.h +135 -0
  65. package/src/native/core/MovingFftFilter.cc +291 -0
  66. package/src/native/core/MovingFftFilter.h +203 -0
  67. package/src/native/core/MovingVarianceFilter.cc +194 -0
  68. package/src/native/core/MovingVarianceFilter.h +114 -0
  69. package/src/native/core/MovingZScoreFilter.cc +215 -0
  70. package/src/native/core/MovingZScoreFilter.h +113 -0
  71. package/src/native/core/Policies.h +352 -0
  72. package/src/native/core/RmsFilter.cc +18 -0
  73. package/src/native/core/RmsFilter.h +131 -0
  74. package/src/native/core/SscFilter.cc +16 -0
  75. package/src/native/core/SscFilter.h +137 -0
  76. package/src/native/core/WampFilter.cc +16 -0
  77. package/src/native/core/WampFilter.h +101 -0
  78. package/src/native/core/WaveformLengthFilter.cc +17 -0
  79. package/src/native/core/WaveformLengthFilter.h +98 -0
  80. package/src/native/utils/CircularBufferArray.cc +336 -0
  81. package/src/native/utils/CircularBufferArray.h +62 -0
  82. package/src/native/utils/CircularBufferVector.cc +145 -0
  83. package/src/native/utils/CircularBufferVector.h +45 -0
  84. package/src/native/utils/NapiUtils.cc +53 -0
  85. package/src/native/utils/NapiUtils.h +21 -0
  86. package/src/native/utils/SimdOps.h +870 -0
  87. package/src/native/utils/SlidingWindowFilter.cc +239 -0
  88. package/src/native/utils/SlidingWindowFilter.h +159 -0
  89. package/src/native/utils/TimeSeriesBuffer.cc +205 -0
  90. package/src/native/utils/TimeSeriesBuffer.h +140 -0
  91. package/src/ts/CircularLogBuffer.ts +87 -0
  92. package/src/ts/DriftDetector.ts +331 -0
  93. package/src/ts/TopicRouter.ts +428 -0
  94. package/src/ts/__tests__/AdvancedDsp.test.ts +585 -0
  95. package/src/ts/__tests__/AuthAndEdgeCases.test.ts +241 -0
  96. package/src/ts/__tests__/Chaining.test.ts +387 -0
  97. package/src/ts/__tests__/ChebyshevBiquad.test.ts +229 -0
  98. package/src/ts/__tests__/CircularLogBuffer.test.ts +158 -0
  99. package/src/ts/__tests__/DriftDetector.test.ts +389 -0
  100. package/src/ts/__tests__/Fft.test.ts +484 -0
  101. package/src/ts/__tests__/ListState.test.ts +153 -0
  102. package/src/ts/__tests__/Logger.test.ts +208 -0
  103. package/src/ts/__tests__/LoggerAdvanced.test.ts +319 -0
  104. package/src/ts/__tests__/LoggerMinor.test.ts +247 -0
  105. package/src/ts/__tests__/MeanAbsoluteValue.test.ts +398 -0
  106. package/src/ts/__tests__/MovingAverage.test.ts +322 -0
  107. package/src/ts/__tests__/RMS.test.ts +315 -0
  108. package/src/ts/__tests__/Rectify.test.ts +272 -0
  109. package/src/ts/__tests__/Redis.test.ts +456 -0
  110. package/src/ts/__tests__/SlopeSignChange.test.ts +166 -0
  111. package/src/ts/__tests__/Tap.test.ts +164 -0
  112. package/src/ts/__tests__/TimeBasedExpiration.test.ts +124 -0
  113. package/src/ts/__tests__/TimeBasedRmsAndMav.test.ts +231 -0
  114. package/src/ts/__tests__/TimeBasedVarianceAndZScore.test.ts +284 -0
  115. package/src/ts/__tests__/TimeSeries.test.ts +254 -0
  116. package/src/ts/__tests__/TopicRouter.test.ts +332 -0
  117. package/src/ts/__tests__/TopicRouterAdvanced.test.ts +483 -0
  118. package/src/ts/__tests__/TopicRouterPriority.test.ts +487 -0
  119. package/src/ts/__tests__/Variance.test.ts +509 -0
  120. package/src/ts/__tests__/WaveformLength.test.ts +147 -0
  121. package/src/ts/__tests__/WillisonAmplitude.test.ts +197 -0
  122. package/src/ts/__tests__/ZScoreNormalize.test.ts +459 -0
  123. package/src/ts/advanced-dsp.ts +566 -0
  124. package/src/ts/backends.ts +1137 -0
  125. package/src/ts/bindings.ts +1225 -0
  126. package/src/ts/easter-egg.ts +42 -0
  127. package/src/ts/examples/MeanAbsoluteValue/test-state.ts +99 -0
  128. package/src/ts/examples/MeanAbsoluteValue/test-streaming.ts +269 -0
  129. package/src/ts/examples/MovingAverage/test-state.ts +85 -0
  130. package/src/ts/examples/MovingAverage/test-streaming.ts +188 -0
  131. package/src/ts/examples/RMS/test-state.ts +97 -0
  132. package/src/ts/examples/RMS/test-streaming.ts +253 -0
  133. package/src/ts/examples/Rectify/test-state.ts +107 -0
  134. package/src/ts/examples/Rectify/test-streaming.ts +242 -0
  135. package/src/ts/examples/Variance/test-state.ts +195 -0
  136. package/src/ts/examples/Variance/test-streaming.ts +260 -0
  137. package/src/ts/examples/ZScoreNormalize/test-state.ts +277 -0
  138. package/src/ts/examples/ZScoreNormalize/test-streaming.ts +306 -0
  139. package/src/ts/examples/advanced-dsp-examples.ts +397 -0
  140. package/src/ts/examples/callbacks/advanced-router-features.ts +326 -0
  141. package/src/ts/examples/callbacks/benchmark-circular-buffer.ts +109 -0
  142. package/src/ts/examples/callbacks/monitoring-example.ts +265 -0
  143. package/src/ts/examples/callbacks/pipeline-callbacks-example.ts +137 -0
  144. package/src/ts/examples/callbacks/pooled-callbacks-example.ts +274 -0
  145. package/src/ts/examples/callbacks/priority-routing-example.ts +277 -0
  146. package/src/ts/examples/callbacks/production-topic-router.ts +214 -0
  147. package/src/ts/examples/callbacks/topic-based-logging.ts +161 -0
  148. package/src/ts/examples/chaining/test-chaining-redis.ts +113 -0
  149. package/src/ts/examples/chaining/test-chaining.ts +52 -0
  150. package/src/ts/examples/emg-features-example.ts +284 -0
  151. package/src/ts/examples/fft-example.ts +309 -0
  152. package/src/ts/examples/fft-examples.ts +349 -0
  153. package/src/ts/examples/filter-examples.ts +320 -0
  154. package/src/ts/examples/list-state-example.ts +131 -0
  155. package/src/ts/examples/logger-example.ts +91 -0
  156. package/src/ts/examples/notch-filter-examples.ts +243 -0
  157. package/src/ts/examples/phase5/drift-detection-example.ts +290 -0
  158. package/src/ts/examples/phase6-7/production-observability.ts +476 -0
  159. package/src/ts/examples/phase6-7/redis-timeseries-integration.ts +446 -0
  160. package/src/ts/examples/redis/redis-example.ts +202 -0
  161. package/src/ts/examples/redis-example.ts +202 -0
  162. package/src/ts/examples/simd-benchmark.ts +126 -0
  163. package/src/ts/examples/tap-debugging.ts +230 -0
  164. package/src/ts/examples/timeseries/comparison-example.ts +290 -0
  165. package/src/ts/examples/timeseries/iot-sensor-example.ts +143 -0
  166. package/src/ts/examples/timeseries/redis-streaming-example.ts +233 -0
  167. package/src/ts/examples/waveform-length-example.ts +139 -0
  168. package/src/ts/fft.ts +722 -0
  169. package/src/ts/filters.ts +1078 -0
  170. package/src/ts/index.ts +120 -0
  171. package/src/ts/types.ts +589 -0
  172. package/tsconfig.json +15 -0
@@ -0,0 +1,352 @@
1
+ #pragma once
2
+ #include <cmath>
3
+ #include <algorithm>
4
+ #include <numeric>
5
+
6
+ namespace dsp::core
7
+ {
8
+ /**
9
+ * @brief Policy for calculating a running mean (for Moving Average).
10
+ *
11
+ * Maintains a running sum and computes the mean on demand.
12
+ */
13
+ template <typename T>
14
+ struct MeanPolicy
15
+ {
16
+ T m_sum = 0;
17
+
18
+ void onAdd(T val) { m_sum += val; }
19
+ void onRemove(T val) { m_sum -= val; }
20
+ void clear() { m_sum = 0; }
21
+
22
+ T getResult(size_t count) const
23
+ {
24
+ if (count == 0)
25
+ return 0;
26
+ return m_sum / static_cast<T>(count);
27
+ }
28
+
29
+ // For state serialization
30
+ T getState() const { return m_sum; }
31
+ void setState(T sum) { m_sum = sum; }
32
+ };
33
+
34
+ /**
35
+ * @brief Policy for calculating RMS (Root Mean Square).
36
+ *
37
+ * Maintains a running sum of squares and computes RMS on demand.
38
+ */
39
+ template <typename T>
40
+ struct RmsPolicy
41
+ {
42
+ T m_sum_sq = 0;
43
+
44
+ void onAdd(T val) { m_sum_sq += (val * val); }
45
+ void onRemove(T val) { m_sum_sq -= (val * val); }
46
+ void clear() { m_sum_sq = 0; }
47
+
48
+ T getResult(size_t count) const
49
+ {
50
+ if (count == 0)
51
+ return 0;
52
+ // Clamp to avoid negative values due to floating-point errors
53
+ T mean_sq = std::max(static_cast<T>(0), m_sum_sq / static_cast<T>(count));
54
+ return std::sqrt(mean_sq);
55
+ }
56
+
57
+ // For state serialization
58
+ T getState() const { return m_sum_sq; }
59
+ void setState(T sumSq) { m_sum_sq = sumSq; }
60
+ };
61
+
62
+ /**
63
+ * @brief Policy for SlidingWindowFilter that maintains a running sum.
64
+ * @tparam T The numeric type (e.g., float, double).
65
+ */
66
+ template <typename T>
67
+ struct SumPolicy
68
+ {
69
+ double m_sum = 0.0;
70
+
71
+ void onAdd(T value)
72
+ {
73
+ m_sum += static_cast<double>(value);
74
+ }
75
+
76
+ void onRemove(T value)
77
+ {
78
+ m_sum -= static_cast<double>(value);
79
+ }
80
+
81
+ void clear()
82
+ {
83
+ m_sum = 0.0;
84
+ }
85
+
86
+ T getResult(size_t count) const
87
+ {
88
+ // The result is just the total sum
89
+ return static_cast<T>(m_sum);
90
+ }
91
+
92
+ // --- State Serialization ---
93
+ double getState() const
94
+ {
95
+ return m_sum;
96
+ }
97
+
98
+ void setState(double state)
99
+ {
100
+ m_sum = state;
101
+ }
102
+
103
+ // Optional: State validation (used in adapter)
104
+ static bool validateState(double state, const std::vector<T> &buffer)
105
+ {
106
+ double actualSum = std::accumulate(buffer.begin(), buffer.end(), 0.0);
107
+ const double tolerance = 0.0001 * std::max(1.0, std::abs(actualSum));
108
+ return (std::abs(state - actualSum) <= tolerance);
109
+ }
110
+ };
111
+
112
+ /**
113
+ * @brief Policy for SlidingWindowFilter that counts 'true' entries.
114
+ */
115
+ struct CounterPolicy
116
+ {
117
+ size_t m_count = 0;
118
+
119
+ void onAdd(bool value)
120
+ {
121
+ if (value)
122
+ {
123
+ m_count++;
124
+ }
125
+ }
126
+
127
+ void onRemove(bool value)
128
+ {
129
+ if (value)
130
+ {
131
+ m_count--;
132
+ }
133
+ }
134
+
135
+ void clear()
136
+ {
137
+ m_count = 0;
138
+ }
139
+
140
+ // Note: The process buffer is float, so we cast the count
141
+ float getResult(size_t count) const
142
+ {
143
+ return static_cast<float>(m_count);
144
+ }
145
+
146
+ // --- State Serialization ---
147
+ size_t getState() const
148
+ {
149
+ return m_count;
150
+ }
151
+
152
+ void setState(size_t state)
153
+ {
154
+ m_count = state;
155
+ }
156
+
157
+ // Optional: State validation (used in adapter)
158
+ static bool validateState(size_t state, const std::vector<bool> &buffer)
159
+ {
160
+ size_t actualCount = 0;
161
+ for (bool val : buffer)
162
+ {
163
+ if (val)
164
+ actualCount++;
165
+ }
166
+ return state == actualCount;
167
+ }
168
+ };
169
+
170
+ /**
171
+ * @brief Policy for calculating Mean Absolute Value (MAV).
172
+ *
173
+ * Maintains a running sum of absolute values.
174
+ */
175
+ template <typename T>
176
+ struct MeanAbsoluteValuePolicy
177
+ {
178
+ T m_sum_abs = 0;
179
+
180
+ void onAdd(T val) { m_sum_abs += std::abs(val); }
181
+ void onRemove(T val) { m_sum_abs -= std::abs(val); }
182
+ void clear() { m_sum_abs = 0; }
183
+
184
+ T getResult(size_t count) const
185
+ {
186
+ if (count == 0)
187
+ return 0;
188
+ return m_sum_abs / static_cast<T>(count);
189
+ }
190
+
191
+ // For state serialization
192
+ T getState() const { return m_sum_abs; }
193
+ void setState(T sumAbs) { m_sum_abs = sumAbs; }
194
+ };
195
+
196
+ /**
197
+ * @brief Policy for calculating Variance.
198
+ *
199
+ * Maintains both sum and sum of squares for variance calculation.
200
+ * Uses the computational formula: Var(X) = E[X²] - (E[X])²
201
+ */
202
+ template <typename T>
203
+ struct VariancePolicy
204
+ {
205
+ T m_sum = 0;
206
+ T m_sum_sq = 0;
207
+
208
+ void onAdd(T val)
209
+ {
210
+ m_sum += val;
211
+ m_sum_sq += (val * val);
212
+ }
213
+
214
+ void onRemove(T val)
215
+ {
216
+ m_sum -= val;
217
+ m_sum_sq -= (val * val);
218
+ }
219
+
220
+ void clear()
221
+ {
222
+ m_sum = 0;
223
+ m_sum_sq = 0;
224
+ }
225
+
226
+ T getResult(size_t count) const
227
+ {
228
+ if (count == 0)
229
+ return 0;
230
+
231
+ T mean = m_sum / static_cast<T>(count);
232
+ T mean_sq = m_sum_sq / static_cast<T>(count);
233
+
234
+ // Clamp to avoid negative variance due to floating-point errors
235
+ return std::max(static_cast<T>(0), mean_sq - (mean * mean));
236
+ }
237
+
238
+ // For state serialization - returns both values as a pair
239
+ std::pair<T, T> getState() const { return {m_sum, m_sum_sq}; }
240
+ void setState(T sum, T sumSq)
241
+ {
242
+ m_sum = sum;
243
+ m_sum_sq = sumSq;
244
+ }
245
+ };
246
+
247
+ /**
248
+ * @brief Policy for calculating Z-Score normalization.
249
+ *
250
+ * Maintains sum and sum of squares to compute mean and stddev,
251
+ * then normalizes values to Z-scores.
252
+ */
253
+ template <typename T>
254
+ struct ZScorePolicy
255
+ {
256
+ T m_sum = 0;
257
+ T m_sum_sq = 0;
258
+ T m_epsilon;
259
+
260
+ explicit ZScorePolicy(T epsilon = static_cast<T>(1e-8))
261
+ : m_epsilon(epsilon) {}
262
+
263
+ void onAdd(T val)
264
+ {
265
+ m_sum += val;
266
+ m_sum_sq += (val * val);
267
+ }
268
+
269
+ void onRemove(T val)
270
+ {
271
+ m_sum -= val;
272
+ m_sum_sq -= (val * val);
273
+ }
274
+
275
+ void clear()
276
+ {
277
+ m_sum = 0;
278
+ m_sum_sq = 0;
279
+ }
280
+
281
+ // Z-Score needs the current value to normalize
282
+ T getResult(T currentValue, size_t count) const
283
+ {
284
+ if (count == 0)
285
+ return 0;
286
+
287
+ T mean = m_sum / static_cast<T>(count);
288
+ T mean_sq = m_sum_sq / static_cast<T>(count);
289
+ T variance = std::max(static_cast<T>(0), mean_sq - (mean * mean));
290
+ T stddev = std::sqrt(variance);
291
+
292
+ // Avoid division by zero
293
+ if (stddev < m_epsilon)
294
+ {
295
+ return 0;
296
+ }
297
+
298
+ return (currentValue - mean) / stddev;
299
+ }
300
+
301
+ // For state serialization
302
+ std::pair<T, T> getState() const { return {m_sum, m_sum_sq}; }
303
+ void setState(T sum, T sumSq)
304
+ {
305
+ m_sum = sum;
306
+ m_sum_sq = sumSq;
307
+ }
308
+
309
+ T getEpsilon() const { return m_epsilon; }
310
+ };
311
+
312
+ /**
313
+ * @brief Policy for FIR filter convolution.
314
+ *
315
+ * Performs FIR filtering using dot product with filter coefficients.
316
+ * The buffer stores recent input samples, and coefficients are the filter taps.
317
+ * Note: SIMD optimization is handled in the FirFilter implementation.
318
+ */
319
+ template <typename T>
320
+ struct FirConvolutionPolicy
321
+ {
322
+ std::vector<T> m_coefficients;
323
+
324
+ explicit FirConvolutionPolicy(const std::vector<T> &coefficients)
325
+ : m_coefficients(coefficients) {}
326
+
327
+ void onAdd(T val) {} // No incremental state to update
328
+ void onRemove(T val) {} // No incremental state to update
329
+ void clear() {} // No state to clear
330
+
331
+ // Compute convolution (dot product) with the buffer
332
+ // Note: This is a simple scalar version; SIMD is applied in FirFilter
333
+ T getResult(const std::vector<T> &buffer) const
334
+ {
335
+ if (buffer.empty() || m_coefficients.empty())
336
+ return T(0);
337
+
338
+ T result = T(0);
339
+ size_t len = std::min(buffer.size(), m_coefficients.size());
340
+ for (size_t i = 0; i < len; ++i)
341
+ {
342
+ result += buffer[i] * m_coefficients[i];
343
+ }
344
+ return result;
345
+ }
346
+
347
+ // For state serialization
348
+ const std::vector<T> &getCoefficients() const { return m_coefficients; }
349
+ void setCoefficients(const std::vector<T> &coeffs) { m_coefficients = coeffs; }
350
+ };
351
+
352
+ } // namespace dsp::core
@@ -0,0 +1,18 @@
1
+ /**
2
+ * @file RmsFilter.cc
3
+ * @brief Implementation file for RmsFilter (now header-only with policy-based design)
4
+ *
5
+ * This file now only contains explicit template instantiations.
6
+ * The actual implementation is in the header file RmsFilter.h,
7
+ * which delegates to SlidingWindowFilter<T, RmsPolicy<T>>.
8
+ */
9
+
10
+ #include "RmsFilter.h"
11
+
12
+ // Explicit template instantiation for common types
13
+ namespace dsp::core
14
+ {
15
+ template class RmsFilter<int>;
16
+ template class RmsFilter<float>;
17
+ template class RmsFilter<double>;
18
+ }
@@ -0,0 +1,131 @@
1
+ #pragma once
2
+ #include "../utils/SlidingWindowFilter.h"
3
+ #include "Policies.h"
4
+ #include <utility>
5
+ #include <vector>
6
+ #include <stdexcept>
7
+
8
+ namespace dsp::core
9
+ {
10
+ using dsp::utils::SlidingWindowFilter;
11
+ /**
12
+ * @brief Implements an efficient Root Mean Square (RMS) filter.
13
+ *
14
+ * This class is now a thin wrapper around SlidingWindowFilter
15
+ * using the RmsPolicy for statistical computation.
16
+ *
17
+ * @tparam T The numeric type of the samples (e.g., float, double).
18
+ */
19
+ template <typename T>
20
+ class RmsFilter
21
+ {
22
+ public:
23
+ /**
24
+ * @brief Constructs a new RMS Filter.
25
+ * @param window_size The number of samples to average over (N).
26
+ */
27
+ explicit RmsFilter(size_t window_size)
28
+ : m_filter(window_size, RmsPolicy<T>{})
29
+ {
30
+ if (window_size == 0)
31
+ {
32
+ throw std::invalid_argument("Window size must be greater than 0");
33
+ }
34
+ }
35
+
36
+ /**
37
+ * @brief Constructs a new time-aware RMS Filter.
38
+ * @param window_size The buffer capacity in samples.
39
+ * @param window_duration_ms The time window duration in milliseconds.
40
+ */
41
+ explicit RmsFilter(size_t window_size, double window_duration_ms)
42
+ : m_filter(window_size, window_duration_ms, RmsPolicy<T>{})
43
+ {
44
+ if (window_size == 0)
45
+ {
46
+ throw std::invalid_argument("Window size must be greater than 0");
47
+ }
48
+ if (window_duration_ms <= 0.0)
49
+ {
50
+ throw std::invalid_argument("Window duration must be greater than 0");
51
+ }
52
+ }
53
+
54
+ // Delete copy constructor and copy assignment
55
+ RmsFilter(const RmsFilter &) = delete;
56
+ RmsFilter &operator=(const RmsFilter &) = delete;
57
+
58
+ // Enable move semantics
59
+ RmsFilter(RmsFilter &&) noexcept = default;
60
+ RmsFilter &operator=(RmsFilter &&) noexcept = default;
61
+
62
+ /**
63
+ * @brief Adds a new sample to the filter.
64
+ * @param newValue The new sample value to add.
65
+ * @return T The new RMS value.
66
+ */
67
+ T addSample(T newValue) { return m_filter.addSample(newValue); }
68
+
69
+ /**
70
+ * @brief Adds a new sample with timestamp (time-aware mode).
71
+ * @param newValue The new sample value to add.
72
+ * @param timestamp The timestamp in milliseconds.
73
+ * @return T The new RMS value.
74
+ */
75
+ T addSampleWithTimestamp(T newValue, double timestamp)
76
+ {
77
+ return m_filter.addSampleWithTimestamp(newValue, timestamp);
78
+ }
79
+
80
+ /**
81
+ * @brief Gets the current RMS value.
82
+ * @return T The RMS of the samples currently in the buffer.
83
+ */
84
+ T getRms() const { return m_filter.getPolicy().getResult(m_filter.getCount()); }
85
+
86
+ /**
87
+ * @brief Clears all samples from the filter and resets the sum.
88
+ */
89
+ void clear() { m_filter.clear(); }
90
+
91
+ /**
92
+ * @brief Checks if the filter's buffer is full (i.e., has N samples).
93
+ * @return true if the buffer is full, false otherwise.
94
+ */
95
+ bool isFull() const noexcept { return m_filter.isFull(); }
96
+
97
+ /**
98
+ * @brief Checks if the filter is in time-aware mode.
99
+ * @return true if time-aware, false otherwise.
100
+ */
101
+ bool isTimeAware() const noexcept { return m_filter.isTimeAware(); }
102
+
103
+ /**
104
+ * @brief Exports the filter's internal state.
105
+ *
106
+ * Delegates to SlidingWindowFilter's generic state management.
107
+ *
108
+ * @return A pair containing the buffer contents and running sum of squares.
109
+ */
110
+ std::pair<std::vector<T>, T> getState() const
111
+ {
112
+ return m_filter.getState();
113
+ }
114
+
115
+ /**
116
+ * @brief Restores the filter's internal state.
117
+ *
118
+ * Delegates to SlidingWindowFilter's generic state management.
119
+ *
120
+ * @param bufferData The buffer contents to restore.
121
+ * @param sumOfSquares The running sum of squares to restore.
122
+ */
123
+ void setState(const std::vector<T> &bufferData, T sumOfSquares)
124
+ {
125
+ m_filter.setState(bufferData, sumOfSquares);
126
+ }
127
+
128
+ private:
129
+ SlidingWindowFilter<T, RmsPolicy<T>> m_filter;
130
+ };
131
+ } // namespace dsp::core
@@ -0,0 +1,16 @@
1
+ /**
2
+ * @file SscFilter.cc
3
+ * @brief Implementation file for SscFilter (now header-only with policy-based design)
4
+ * This file now only contains explicit template instantiations.
5
+ * The actual implementation is in the header file SscFilter.h,
6
+ * which delegates to SlidingWindowFilter<T, CounterPolicy>.
7
+ */
8
+
9
+ #include "SscFilter.h"
10
+
11
+ // Explicit template instantiation for common types
12
+ namespace dsp::core
13
+ {
14
+ template class SscFilter<float>;
15
+ template class SscFilter<double>;
16
+ } // namespace dsp::core
@@ -0,0 +1,137 @@
1
+ #pragma once
2
+
3
+ #include "../utils/SlidingWindowFilter.h"
4
+ #include "Policies.h"
5
+ #include <cmath> // For std::abs
6
+ #include <utility> // For std::pair
7
+ #include <vector>
8
+
9
+ namespace dsp::core
10
+ {
11
+ template <typename T>
12
+ class SscFilter
13
+ {
14
+ public:
15
+ /**
16
+ * @brief Constructs a new Ssc Filter.
17
+ * @param window_size The number of samples to consider in the sliding window.
18
+ * @param threshold The amplitude change threshold to detect.
19
+ */
20
+ explicit SscFilter(size_t window_size, T threshold)
21
+ : m_filter(window_size),
22
+ m_threshold(threshold),
23
+ m_sample_minus_1(0.0),
24
+ m_sample_minus_2(0.0),
25
+ m_init_count(0) {}
26
+
27
+ // Delete copy constructor and copy assignment
28
+ SscFilter(const SscFilter &) = delete;
29
+ SscFilter &operator=(const SscFilter &) = delete;
30
+
31
+ // Enable move semantics
32
+ SscFilter(SscFilter &&) noexcept = default;
33
+ SscFilter &operator=(SscFilter &&) noexcept = default;
34
+
35
+ /**
36
+ * @brief Adds a new sample to the filter.
37
+ * @param sample_n The new sample value to add.
38
+ * @return T The updated SSC count over the window.
39
+ */
40
+ T addSample(T sample_n) // sample_n is x_{i+1}
41
+ {
42
+ bool did_change = false;
43
+
44
+ if (m_init_count >= 2)
45
+ {
46
+ // We have x_{i-1} (m_sample_minus_2), x_i (m_sample_minus_1), and x_{i+1} (sample_n)
47
+ T diff1 = m_sample_minus_1 - m_sample_minus_2; // (x_i - x_{i-1})
48
+ T diff2 = m_sample_minus_1 - sample_n; // (x_i - x_{i+1})
49
+
50
+ did_change = (diff1 * diff2) > m_threshold;
51
+ }
52
+ else
53
+ {
54
+ if (m_init_count == 0)
55
+ m_sample_minus_2 = sample_n; // First sample
56
+ if (m_init_count == 1)
57
+ m_sample_minus_1 = sample_n; // Second sample
58
+ m_init_count++;
59
+ }
60
+
61
+ // Update state for the *next* iteration
62
+ m_sample_minus_2 = m_sample_minus_1;
63
+ m_sample_minus_1 = sample_n;
64
+
65
+ // Add the boolean to the window, get the count back
66
+ // Cast count (size_t) to T (float/double)
67
+ return static_cast<T>(m_filter.addSample(did_change));
68
+ }
69
+
70
+ /**
71
+ * @brief Clears all samples from the filter and resets state.
72
+ */
73
+ void clear()
74
+ {
75
+ m_filter.clear();
76
+ m_sample_minus_1 = 0.0;
77
+ m_sample_minus_2 = 0.0;
78
+ m_init_count = 0;
79
+ }
80
+
81
+ // --- State Management ---
82
+ using SscState = std::pair<std::vector<bool>, size_t>;
83
+
84
+ struct SscFilterState
85
+ {
86
+ T sample_minus_1;
87
+ T sample_minus_2;
88
+ int init_count;
89
+ };
90
+
91
+ /**
92
+ * @brief Exports the complete filter state (buffer + previous samples).
93
+ * @return A pair containing the buffer contents, running count, and previous samples.
94
+ */
95
+
96
+ auto getState() const -> std::pair<SscState, SscFilterState>
97
+ {
98
+ // Returns: { {buffer_of_bools, running_count}, {s_m1, s_m2, init_count} }
99
+ return {
100
+ m_filter.getState(),
101
+ {m_sample_minus_1, m_sample_minus_2, m_init_count}};
102
+ }
103
+
104
+ /**
105
+ * @brief Restores the complete filter state (buffer + previous samples).
106
+ * @param buffer The buffer contents to restore.
107
+ * @param count The count of 'true' entries in the buffer.
108
+ * @param filterState The previous samples and init count to restore.
109
+ * @return void
110
+ */
111
+
112
+ void setState(const std::vector<bool> &buffer, size_t count, const SscFilterState &filterState)
113
+ {
114
+ m_filter.setState(buffer, count);
115
+ m_sample_minus_1 = filterState.sample_minus_1;
116
+ m_sample_minus_2 = filterState.sample_minus_2;
117
+ m_init_count = filterState.init_count;
118
+ }
119
+
120
+ /**
121
+ * @brief Gets const access to the internal SlidingWindowFilter.
122
+ * @return const SlidingWindowFilter<bool, CounterPolicy>& Reference to the internal filter
123
+ */
124
+ const dsp::utils::SlidingWindowFilter<bool, CounterPolicy> &getInternalFilter() const
125
+ {
126
+ return m_filter;
127
+ }
128
+
129
+ private:
130
+ dsp::utils::SlidingWindowFilter<bool, CounterPolicy> m_filter;
131
+ T m_threshold;
132
+ T m_sample_minus_1; // x_i
133
+ T m_sample_minus_2; // x_{i-1}
134
+ int m_init_count; // Needs 2 samples to be fully initialized
135
+ };
136
+
137
+ } // namespace dsp::core
@@ -0,0 +1,16 @@
1
+ /**
2
+ * @file WampFilter.cc
3
+ * @brief Implementation file for WampFilter (now header-only with policy-based design)
4
+ * This file now only contains explicit template instantiations.
5
+ * The actual implementation is in the header file WampFilter.h,
6
+ * which delegates to SlidingWindowFilter<T, CounterPolicy>.
7
+ */
8
+
9
+ #include "WampFilter.h"
10
+
11
+ // Explicit template instantiation for common types
12
+ namespace dsp::core
13
+ {
14
+ template class WampFilter<float>;
15
+ template class WampFilter<double>;
16
+ }