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,210 @@
1
+ /**
2
+ * IIR (Infinite Impulse Response) Filter
3
+ *
4
+ * A recursive filter defined by:
5
+ * y[n] = (b[0]*x[n] + b[1]*x[n-1] + ... + b[M]*x[n-M])
6
+ * - (a[1]*y[n-1] + a[2]*y[n-2] + ... + a[N]*y[n-N])
7
+ *
8
+ * Standard form: a[0] = 1 (normalized)
9
+ *
10
+ * Features:
11
+ * - Feedback structure (can be unstable if poles outside unit circle)
12
+ * - Efficient (fewer coefficients than FIR for same frequency response)
13
+ * - Stateful (maintains input/output history) and stateless modes
14
+ * - Common filter designs: Butterworth, Chebyshev, Bessel
15
+ * - Biquad cascade structure for numerical stability
16
+ */
17
+
18
+ #ifndef DSP_CORE_IIR_FILTER_H
19
+ #define DSP_CORE_IIR_FILTER_H
20
+
21
+ #include <vector>
22
+ #include <cstddef>
23
+ #include <memory>
24
+
25
+ namespace dsp
26
+ {
27
+ namespace core
28
+ {
29
+
30
+ template <typename T = float>
31
+ class IirFilter
32
+ {
33
+ public:
34
+ /**
35
+ * Constructor
36
+ * @param b_coeffs Feedforward coefficients (b[0], b[1], ..., b[M])
37
+ * @param a_coeffs Feedback coefficients (a[1], a[2], ..., a[N])
38
+ * Note: a[0] is assumed to be 1 (normalized form)
39
+ * @param stateful If true, maintains state between process calls
40
+ */
41
+ IirFilter(const std::vector<T> &b_coeffs, const std::vector<T> &a_coeffs, bool stateful = true);
42
+
43
+ /**
44
+ * Process single sample (stateful mode only)
45
+ * @param input Input sample
46
+ * @return Filtered output sample
47
+ */
48
+ T processSample(T input);
49
+
50
+ /**
51
+ * Process batch of samples
52
+ * @param input Input samples
53
+ * @param output Output buffer (must be same size as input)
54
+ * @param length Number of samples
55
+ * @param stateless If true, ignores internal state (batch processing)
56
+ */
57
+ void process(const T *input, T *output, size_t length, bool stateless = false);
58
+
59
+ /**
60
+ * Reset filter state (clear history)
61
+ */
62
+ void reset();
63
+
64
+ /**
65
+ * Get feedforward order (M)
66
+ */
67
+ size_t getFeedforwardOrder() const { return m_b_coeffs.size() - 1; }
68
+
69
+ /**
70
+ * Get feedback order (N)
71
+ */
72
+ size_t getFeedbackOrder() const { return m_a_coeffs.size(); }
73
+
74
+ /**
75
+ * Get feedforward coefficients
76
+ */
77
+ const std::vector<T> &getBCoefficients() const { return m_b_coeffs; }
78
+
79
+ /**
80
+ * Get feedback coefficients
81
+ */
82
+ const std::vector<T> &getACoefficients() const { return m_a_coeffs; }
83
+
84
+ /**
85
+ * Update coefficients (resets state)
86
+ */
87
+ void setCoefficients(const std::vector<T> &b_coeffs, const std::vector<T> &a_coeffs);
88
+
89
+ /**
90
+ * Check if filter is stateful
91
+ */
92
+ bool isStateful() const { return m_stateful; }
93
+
94
+ /**
95
+ * Check filter stability (all poles inside unit circle)
96
+ * Note: This is a basic check; full stability analysis requires pole computation
97
+ */
98
+ bool isStable() const;
99
+
100
+ // ========== Common IIR Filter Designs ==========
101
+
102
+ /**
103
+ * Create Butterworth low-pass filter (maximally flat passband)
104
+ * @param cutoffFreq Cutoff frequency (normalized: 0 to 0.5)
105
+ * @param order Filter order (1-8 recommended)
106
+ * @return IIR filter
107
+ */
108
+ static IirFilter<T> createButterworthLowPass(T cutoffFreq, int order);
109
+
110
+ /**
111
+ * Create Butterworth high-pass filter
112
+ * @param cutoffFreq Cutoff frequency (normalized: 0 to 0.5)
113
+ * @param order Filter order (1-8 recommended)
114
+ */
115
+ static IirFilter<T> createButterworthHighPass(T cutoffFreq, int order);
116
+
117
+ /**
118
+ * Create Butterworth band-pass filter
119
+ * @param lowCutoff Low cutoff frequency (normalized)
120
+ * @param highCutoff High cutoff frequency (normalized)
121
+ * @param order Filter order (per band, total = 2*order)
122
+ */
123
+ static IirFilter<T> createButterworthBandPass(T lowCutoff, T highCutoff, int order);
124
+
125
+ /**
126
+ * Create first-order low-pass filter (simple RC filter)
127
+ * @param cutoffFreq Cutoff frequency (normalized: 0 to 0.5)
128
+ */
129
+ static IirFilter<T> createFirstOrderLowPass(T cutoffFreq);
130
+
131
+ /**
132
+ * Create first-order high-pass filter
133
+ * @param cutoffFreq Cutoff frequency (normalized: 0 to 0.5)
134
+ */
135
+ static IirFilter<T> createFirstOrderHighPass(T cutoffFreq);
136
+
137
+ /**
138
+ * Create biquad filter from biquad coefficients
139
+ * y[n] = b0*x[n] + b1*x[n-1] + b2*x[n-2] - a1*y[n-1] - a2*y[n-2]
140
+ */
141
+ static IirFilter<T> createBiquad(T b0, T b1, T b2, T a1, T a2);
142
+
143
+ /**
144
+ * Create Chebyshev Type I low-pass filter (passband ripple)
145
+ * @param cutoffFreq Cutoff frequency (normalized: 0 to 0.5)
146
+ * @param order Filter order (1-8 recommended)
147
+ * @param rippleDb Passband ripple in dB (0.1 to 3.0, typical: 0.5)
148
+ * @return IIR filter
149
+ */
150
+ static IirFilter<T> createChebyshevLowPass(T cutoffFreq, int order, T rippleDb = T(0.5));
151
+
152
+ /**
153
+ * Create Chebyshev Type I high-pass filter (passband ripple)
154
+ * @param cutoffFreq Cutoff frequency (normalized: 0 to 0.5)
155
+ * @param order Filter order (1-8 recommended)
156
+ * @param rippleDb Passband ripple in dB (0.1 to 3.0, typical: 0.5)
157
+ */
158
+ static IirFilter<T> createChebyshevHighPass(T cutoffFreq, int order, T rippleDb = T(0.5));
159
+
160
+ /**
161
+ * Create Chebyshev Type I band-pass filter (passband ripple)
162
+ * @param lowCutoff Low cutoff frequency (normalized)
163
+ * @param highCutoff High cutoff frequency (normalized)
164
+ * @param order Filter order (per band, total = 2*order)
165
+ * @param rippleDb Passband ripple in dB (0.1 to 3.0, typical: 0.5)
166
+ */
167
+ static IirFilter<T> createChebyshevBandPass(T lowCutoff, T highCutoff, int order, T rippleDb = T(0.5));
168
+
169
+ /**
170
+ * Create peaking EQ biquad filter
171
+ * @param centerFreq Center frequency (normalized: 0 to 0.5)
172
+ * @param Q Quality factor (bandwidth = centerFreq/Q, typical: 0.5-10)
173
+ * @param gainDb Gain in dB (negative for cut, positive for boost)
174
+ */
175
+ static IirFilter<T> createPeakingEQ(T centerFreq, T Q, T gainDb);
176
+
177
+ /**
178
+ * Create low-shelf biquad filter
179
+ * @param cutoffFreq Cutoff frequency (normalized: 0 to 0.5)
180
+ * @param gainDb Gain in dB for low frequencies
181
+ * @param Q Shelf slope (typical: 0.7)
182
+ */
183
+ static IirFilter<T> createLowShelf(T cutoffFreq, T gainDb, T Q = T(0.707));
184
+
185
+ /**
186
+ * Create high-shelf biquad filter
187
+ * @param cutoffFreq Cutoff frequency (normalized: 0 to 0.5)
188
+ * @param gainDb Gain in dB for high frequencies
189
+ * @param Q Shelf slope (typical: 0.7)
190
+ */
191
+ static IirFilter<T> createHighShelf(T cutoffFreq, T gainDb, T Q = T(0.707));
192
+
193
+ private:
194
+ std::vector<T> m_b_coeffs; // Feedforward coefficients (b[0], b[1], ..., b[M])
195
+ std::vector<T> m_a_coeffs; // Feedback coefficients (a[1], a[2], ..., a[N])
196
+ std::vector<T> m_x_state; // Input history (x[n-1], x[n-2], ...)
197
+ std::vector<T> m_y_state; // Output history (y[n-1], y[n-2], ...)
198
+ bool m_stateful; // Whether to maintain state between calls
199
+
200
+ /**
201
+ * Bilinear transform: convert analog to digital filter
202
+ * s -> 2/T * (1 - z^-1) / (1 + z^-1)
203
+ */
204
+ static void bilinearTransform(T wc, int order, std::vector<T> &b, std::vector<T> &a);
205
+ };
206
+
207
+ } // namespace core
208
+ } // namespace dsp
209
+
210
+ #endif // DSP_CORE_IIR_FILTER_H
@@ -0,0 +1,17 @@
1
+ /**
2
+ * @file MovingAbsoluteValueFilter.cc
3
+ * @brief Implementation file for MovingAbsoluteValueFilter (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 MovingAbsoluteValueFilter.h,
7
+ * which delegates to SlidingWindowFilter<T, MeanAbsoluteValuePolicy<T>>.
8
+ */
9
+
10
+ #include "MovingAbsoluteValueFilter.h"
11
+
12
+ // Explicit template instantiation for common types
13
+ namespace dsp::core
14
+ {
15
+ template class MovingAbsoluteValueFilter<float>;
16
+ template class MovingAbsoluteValueFilter<double>;
17
+ }
@@ -0,0 +1,135 @@
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 Mean Absolute Value (MAV) filter.
13
+ *
14
+ * This class is now a thin wrapper around SlidingWindowFilter
15
+ * using the MeanAbsoluteValuePolicy for statistical computation.
16
+ *
17
+ * The policy automatically handles the absolute value calculation,
18
+ * demonstrating the power of policy-based design for complex transformations.
19
+ *
20
+ * @tparam T The numeric type of the samples (e.g., float, double, int).
21
+ */
22
+ template <typename T>
23
+ class MovingAbsoluteValueFilter
24
+ {
25
+ public:
26
+ /**
27
+ * @brief Constructs a new MAV Filter.
28
+ * @param window_size The number of samples to average over (N).
29
+ */
30
+ explicit MovingAbsoluteValueFilter(size_t window_size)
31
+ : m_filter(window_size, MeanAbsoluteValuePolicy<T>{})
32
+ {
33
+ if (window_size == 0)
34
+ {
35
+ throw std::invalid_argument("Window size must be greater than 0");
36
+ }
37
+ }
38
+
39
+ /**
40
+ * @brief Constructs a new time-aware MAV Filter.
41
+ * @param window_size The buffer capacity in samples.
42
+ * @param window_duration_ms The time window duration in milliseconds.
43
+ */
44
+ explicit MovingAbsoluteValueFilter(size_t window_size, double window_duration_ms)
45
+ : m_filter(window_size, window_duration_ms, MeanAbsoluteValuePolicy<T>{})
46
+ {
47
+ if (window_size == 0)
48
+ {
49
+ throw std::invalid_argument("Window size must be greater than 0");
50
+ }
51
+ if (window_duration_ms <= 0.0)
52
+ {
53
+ throw std::invalid_argument("Window duration must be greater than 0");
54
+ }
55
+ }
56
+
57
+ // Delete copy constructor and copy assignment
58
+ MovingAbsoluteValueFilter(const MovingAbsoluteValueFilter &) = delete;
59
+ MovingAbsoluteValueFilter &operator=(const MovingAbsoluteValueFilter &) = delete;
60
+
61
+ // Enable move semantics
62
+ MovingAbsoluteValueFilter(MovingAbsoluteValueFilter &&) noexcept = default;
63
+ MovingAbsoluteValueFilter &operator=(MovingAbsoluteValueFilter &&) noexcept = default;
64
+
65
+ /**
66
+ * @brief Adds a new sample to the filter.
67
+ * @param newValue The new sample value to add (can be negative).
68
+ * @return T The new mean absolute value.
69
+ */
70
+ T addSample(T newValue) { return m_filter.addSample(newValue); }
71
+
72
+ /**
73
+ * @brief Adds a new sample with timestamp (time-aware mode).
74
+ * @param newValue The new sample value to add (can be negative).
75
+ * @param timestamp The timestamp in milliseconds.
76
+ * @return T The new mean absolute value.
77
+ */
78
+ T addSampleWithTimestamp(T newValue, double timestamp)
79
+ {
80
+ return m_filter.addSampleWithTimestamp(newValue, timestamp);
81
+ }
82
+
83
+ /**
84
+ * @brief Gets the current mean absolute value.
85
+ * @return T The MAV of the samples currently in the buffer.
86
+ */
87
+ T getMav() const { return m_filter.getPolicy().getResult(m_filter.getCount()); }
88
+
89
+ /**
90
+ * @brief Clears all samples from the filter and resets the sum.
91
+ */
92
+ void clear() { m_filter.clear(); }
93
+
94
+ /**
95
+ * @brief Checks if the filter's buffer is full (i.e., has N samples).
96
+ * @return true if the buffer is full, false otherwise.
97
+ */
98
+ bool isFull() const noexcept { return m_filter.isFull(); }
99
+
100
+ /**
101
+ * @brief Checks if the filter is in time-aware mode.
102
+ * @return true if time-aware, false otherwise.
103
+ */
104
+ bool isTimeAware() const noexcept { return m_filter.isTimeAware(); }
105
+
106
+ /**
107
+ * @brief Exports the filter's internal state.
108
+ *
109
+ * Delegates to SlidingWindowFilter's generic state management.
110
+ *
111
+ * @return A pair containing the buffer contents (original values)
112
+ * and the running sum of absolute values.
113
+ */
114
+ std::pair<std::vector<T>, T> getState() const
115
+ {
116
+ return m_filter.getState();
117
+ }
118
+
119
+ /**
120
+ * @brief Restores the filter's internal state.
121
+ *
122
+ * Delegates to SlidingWindowFilter's generic state management.
123
+ *
124
+ * @param bufferData The buffer contents (original values) to restore.
125
+ * @param sumOfAbs The running sum of absolute values to restore.
126
+ */
127
+ void setState(const std::vector<T> &bufferData, T sumOfAbs)
128
+ {
129
+ m_filter.setState(bufferData, sumOfAbs);
130
+ }
131
+
132
+ private:
133
+ SlidingWindowFilter<T, MeanAbsoluteValuePolicy<T>> m_filter;
134
+ };
135
+ } // namespace dsp::core
@@ -0,0 +1,18 @@
1
+ /**
2
+ * @file MovingAverageFilter.cc
3
+ * @brief Implementation file for MovingAverageFilter (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 MovingAverageFilter.h,
7
+ * which delegates to SlidingWindowFilter<T, MeanPolicy<T>>.
8
+ */
9
+
10
+ #include "MovingAverageFilter.h"
11
+
12
+ // Explicit template instantiation for common types
13
+ namespace dsp::core
14
+ {
15
+ template class MovingAverageFilter<int>;
16
+ template class MovingAverageFilter<float>;
17
+ template class MovingAverageFilter<double>;
18
+ }
@@ -0,0 +1,135 @@
1
+ #pragma once
2
+ #include "../utils/SlidingWindowFilter.h"
3
+ #include "Policies.h"
4
+ #include <utility>
5
+ #include <vector>
6
+
7
+ namespace dsp::core
8
+ {
9
+ using dsp::utils::SlidingWindowFilter;
10
+ /**
11
+ * @brief Implements an efficient Simple Moving Average (SMA) filter.
12
+ *
13
+ * This class is now a thin wrapper around SlidingWindowFilter
14
+ * using the MeanPolicy for statistical computation.
15
+ *
16
+ * The policy-based design provides:
17
+ * - Zero-cost abstraction (inlined policy methods)
18
+ * - Consistent interface across all sliding window filters
19
+ * - Easy extensibility for new statistical measures
20
+ *
21
+ * @tparam T The numeric type of the samples (e.g., float, double, int).
22
+ */
23
+ template <typename T>
24
+ class MovingAverageFilter
25
+ {
26
+ public:
27
+ /**
28
+ * @brief Constructs a new Moving Average Filter.
29
+ * @param window_size The number of samples to average over (N).
30
+ */
31
+ explicit MovingAverageFilter(size_t window_size)
32
+ : m_filter(window_size, MeanPolicy<T>{})
33
+ {
34
+ if (window_size == 0)
35
+ {
36
+ throw std::invalid_argument("Window size must be greater than 0");
37
+ }
38
+ }
39
+
40
+ /**
41
+ * @brief Constructs a new time-aware Moving Average Filter.
42
+ * @param window_size The number of samples to average over (N).
43
+ * @param window_duration_ms The maximum age of samples in milliseconds.
44
+ */
45
+ explicit MovingAverageFilter(size_t window_size, double window_duration_ms)
46
+ : m_filter(window_size, window_duration_ms, MeanPolicy<T>{})
47
+ {
48
+ if (window_size == 0)
49
+ {
50
+ throw std::invalid_argument("Window size must be greater than 0");
51
+ }
52
+ if (window_duration_ms <= 0.0)
53
+ {
54
+ throw std::invalid_argument("Window duration must be positive");
55
+ }
56
+ }
57
+
58
+ // Delete copy constructor and copy assignment
59
+ MovingAverageFilter(const MovingAverageFilter &) = delete;
60
+ MovingAverageFilter &operator=(const MovingAverageFilter &) = delete;
61
+
62
+ // Enable move semantics
63
+ MovingAverageFilter(MovingAverageFilter &&) noexcept = default;
64
+ MovingAverageFilter &operator=(MovingAverageFilter &&) noexcept = default;
65
+
66
+ /**
67
+ * @brief Adds a new sample to the filter.
68
+ * @param newValue The new sample value to add.
69
+ * @return T The new moving average.
70
+ */
71
+ T addSample(T newValue) { return m_filter.addSample(newValue); }
72
+
73
+ /**
74
+ * @brief Adds a new sample with timestamp (time-aware mode only).
75
+ * @param newValue The new sample value to add.
76
+ * @param timestamp The timestamp in milliseconds.
77
+ * @return T The new moving average.
78
+ */
79
+ T addSampleWithTimestamp(T newValue, double timestamp)
80
+ {
81
+ return m_filter.addSampleWithTimestamp(newValue, timestamp);
82
+ }
83
+
84
+ /**
85
+ * @brief Checks if this is a time-aware filter.
86
+ * @return bool True if window duration is set.
87
+ */
88
+ bool isTimeAware() const noexcept { return m_filter.isTimeAware(); }
89
+
90
+ /**
91
+ * @brief Gets the current moving average.
92
+ * @return T The average of the samples currently in the buffer.
93
+ */
94
+ T getAverage() const { return m_filter.getPolicy().getResult(m_filter.getCount()); }
95
+
96
+ /**
97
+ * @brief Clears all samples from the filter and resets the sum.
98
+ */
99
+ void clear() { m_filter.clear(); }
100
+
101
+ /**
102
+ * @brief Checks if the filter's buffer is full (i.e., has N samples).
103
+ * @return true if the buffer is full, false otherwise.
104
+ */
105
+ bool isFull() const noexcept { return m_filter.isFull(); }
106
+
107
+ /**
108
+ * @brief Exports the filter's internal state.
109
+ *
110
+ * Delegates to SlidingWindowFilter's generic state management.
111
+ *
112
+ * @return A pair containing the buffer contents and running sum.
113
+ */
114
+ std::pair<std::vector<T>, T> getState() const
115
+ {
116
+ return m_filter.getState();
117
+ }
118
+
119
+ /**
120
+ * @brief Restores the filter's internal state.
121
+ *
122
+ * Delegates to SlidingWindowFilter's generic state management.
123
+ *
124
+ * @param bufferData The buffer contents to restore.
125
+ * @param sum The running sum to restore.
126
+ */
127
+ void setState(const std::vector<T> &bufferData, T sum)
128
+ {
129
+ m_filter.setState(bufferData, sum);
130
+ }
131
+
132
+ private:
133
+ SlidingWindowFilter<T, MeanPolicy<T>> m_filter;
134
+ };
135
+ } // namespace dsp::core