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.
- package/.github/workflows/ci.yml +185 -0
- package/.vscode/c_cpp_properties.json +17 -0
- package/.vscode/settings.json +68 -0
- package/.vscode/tasks.json +28 -0
- package/DISCLAIMER.md +32 -0
- package/LICENSE +21 -0
- package/README.md +1803 -0
- package/ROADMAP.md +192 -0
- package/TECHNICAL_DEBT.md +165 -0
- package/binding.gyp +65 -0
- package/docs/ADVANCED_LOGGER_FEATURES.md +598 -0
- package/docs/AUTHENTICATION_SECURITY.md +396 -0
- package/docs/BACKEND_IMPROVEMENTS.md +399 -0
- package/docs/CHEBYSHEV_BIQUAD_EQ_IMPLEMENTATION.md +405 -0
- package/docs/FFT_IMPLEMENTATION.md +490 -0
- package/docs/FFT_IMPROVEMENTS_SUMMARY.md +387 -0
- package/docs/FFT_USER_GUIDE.md +494 -0
- package/docs/FILTERS_IMPLEMENTATION.md +260 -0
- package/docs/FILTER_API_GUIDE.md +418 -0
- package/docs/FIR_SIMD_OPTIMIZATION.md +175 -0
- package/docs/LOGGER_API_REFERENCE.md +350 -0
- package/docs/NOTCH_FILTER_QUICK_REF.md +121 -0
- package/docs/PHASE2_TESTS_AND_NOTCH_FILTER.md +341 -0
- package/docs/PHASES_5_7_SUMMARY.md +403 -0
- package/docs/PIPELINE_FILTER_INTEGRATION.md +446 -0
- package/docs/SIMD_OPTIMIZATIONS.md +211 -0
- package/docs/TEST_MIGRATION_SUMMARY.md +173 -0
- package/docs/TIMESERIES_IMPLEMENTATION_SUMMARY.md +322 -0
- package/docs/TIMESERIES_QUICK_REF.md +85 -0
- package/docs/advanced.md +559 -0
- package/docs/time-series-guide.md +617 -0
- package/docs/time-series-migration.md +376 -0
- package/jest.config.js +37 -0
- package/package.json +42 -0
- package/prebuilds/linux-x64/dsp-ts-redis.node +0 -0
- package/prebuilds/win32-x64/dsp-ts-redis.node +0 -0
- package/scripts/test.js +24 -0
- package/src/build/dsp-ts-redis.node +0 -0
- package/src/native/DspPipeline.cc +675 -0
- package/src/native/DspPipeline.h +44 -0
- package/src/native/FftBindings.cc +817 -0
- package/src/native/FilterBindings.cc +1001 -0
- package/src/native/IDspStage.h +53 -0
- package/src/native/adapters/InterpolatorStage.h +201 -0
- package/src/native/adapters/MeanAbsoluteValueStage.h +289 -0
- package/src/native/adapters/MovingAverageStage.h +306 -0
- package/src/native/adapters/RectifyStage.h +88 -0
- package/src/native/adapters/ResamplerStage.h +238 -0
- package/src/native/adapters/RmsStage.h +299 -0
- package/src/native/adapters/SscStage.h +121 -0
- package/src/native/adapters/VarianceStage.h +307 -0
- package/src/native/adapters/WampStage.h +114 -0
- package/src/native/adapters/WaveformLengthStage.h +115 -0
- package/src/native/adapters/ZScoreNormalizeStage.h +326 -0
- package/src/native/core/FftEngine.cc +441 -0
- package/src/native/core/FftEngine.h +224 -0
- package/src/native/core/FirFilter.cc +324 -0
- package/src/native/core/FirFilter.h +149 -0
- package/src/native/core/IirFilter.cc +576 -0
- package/src/native/core/IirFilter.h +210 -0
- package/src/native/core/MovingAbsoluteValueFilter.cc +17 -0
- package/src/native/core/MovingAbsoluteValueFilter.h +135 -0
- package/src/native/core/MovingAverageFilter.cc +18 -0
- package/src/native/core/MovingAverageFilter.h +135 -0
- package/src/native/core/MovingFftFilter.cc +291 -0
- package/src/native/core/MovingFftFilter.h +203 -0
- package/src/native/core/MovingVarianceFilter.cc +194 -0
- package/src/native/core/MovingVarianceFilter.h +114 -0
- package/src/native/core/MovingZScoreFilter.cc +215 -0
- package/src/native/core/MovingZScoreFilter.h +113 -0
- package/src/native/core/Policies.h +352 -0
- package/src/native/core/RmsFilter.cc +18 -0
- package/src/native/core/RmsFilter.h +131 -0
- package/src/native/core/SscFilter.cc +16 -0
- package/src/native/core/SscFilter.h +137 -0
- package/src/native/core/WampFilter.cc +16 -0
- package/src/native/core/WampFilter.h +101 -0
- package/src/native/core/WaveformLengthFilter.cc +17 -0
- package/src/native/core/WaveformLengthFilter.h +98 -0
- package/src/native/utils/CircularBufferArray.cc +336 -0
- package/src/native/utils/CircularBufferArray.h +62 -0
- package/src/native/utils/CircularBufferVector.cc +145 -0
- package/src/native/utils/CircularBufferVector.h +45 -0
- package/src/native/utils/NapiUtils.cc +53 -0
- package/src/native/utils/NapiUtils.h +21 -0
- package/src/native/utils/SimdOps.h +870 -0
- package/src/native/utils/SlidingWindowFilter.cc +239 -0
- package/src/native/utils/SlidingWindowFilter.h +159 -0
- package/src/native/utils/TimeSeriesBuffer.cc +205 -0
- package/src/native/utils/TimeSeriesBuffer.h +140 -0
- package/src/ts/CircularLogBuffer.ts +87 -0
- package/src/ts/DriftDetector.ts +331 -0
- package/src/ts/TopicRouter.ts +428 -0
- package/src/ts/__tests__/AdvancedDsp.test.ts +585 -0
- package/src/ts/__tests__/AuthAndEdgeCases.test.ts +241 -0
- package/src/ts/__tests__/Chaining.test.ts +387 -0
- package/src/ts/__tests__/ChebyshevBiquad.test.ts +229 -0
- package/src/ts/__tests__/CircularLogBuffer.test.ts +158 -0
- package/src/ts/__tests__/DriftDetector.test.ts +389 -0
- package/src/ts/__tests__/Fft.test.ts +484 -0
- package/src/ts/__tests__/ListState.test.ts +153 -0
- package/src/ts/__tests__/Logger.test.ts +208 -0
- package/src/ts/__tests__/LoggerAdvanced.test.ts +319 -0
- package/src/ts/__tests__/LoggerMinor.test.ts +247 -0
- package/src/ts/__tests__/MeanAbsoluteValue.test.ts +398 -0
- package/src/ts/__tests__/MovingAverage.test.ts +322 -0
- package/src/ts/__tests__/RMS.test.ts +315 -0
- package/src/ts/__tests__/Rectify.test.ts +272 -0
- package/src/ts/__tests__/Redis.test.ts +456 -0
- package/src/ts/__tests__/SlopeSignChange.test.ts +166 -0
- package/src/ts/__tests__/Tap.test.ts +164 -0
- package/src/ts/__tests__/TimeBasedExpiration.test.ts +124 -0
- package/src/ts/__tests__/TimeBasedRmsAndMav.test.ts +231 -0
- package/src/ts/__tests__/TimeBasedVarianceAndZScore.test.ts +284 -0
- package/src/ts/__tests__/TimeSeries.test.ts +254 -0
- package/src/ts/__tests__/TopicRouter.test.ts +332 -0
- package/src/ts/__tests__/TopicRouterAdvanced.test.ts +483 -0
- package/src/ts/__tests__/TopicRouterPriority.test.ts +487 -0
- package/src/ts/__tests__/Variance.test.ts +509 -0
- package/src/ts/__tests__/WaveformLength.test.ts +147 -0
- package/src/ts/__tests__/WillisonAmplitude.test.ts +197 -0
- package/src/ts/__tests__/ZScoreNormalize.test.ts +459 -0
- package/src/ts/advanced-dsp.ts +566 -0
- package/src/ts/backends.ts +1137 -0
- package/src/ts/bindings.ts +1225 -0
- package/src/ts/easter-egg.ts +42 -0
- package/src/ts/examples/MeanAbsoluteValue/test-state.ts +99 -0
- package/src/ts/examples/MeanAbsoluteValue/test-streaming.ts +269 -0
- package/src/ts/examples/MovingAverage/test-state.ts +85 -0
- package/src/ts/examples/MovingAverage/test-streaming.ts +188 -0
- package/src/ts/examples/RMS/test-state.ts +97 -0
- package/src/ts/examples/RMS/test-streaming.ts +253 -0
- package/src/ts/examples/Rectify/test-state.ts +107 -0
- package/src/ts/examples/Rectify/test-streaming.ts +242 -0
- package/src/ts/examples/Variance/test-state.ts +195 -0
- package/src/ts/examples/Variance/test-streaming.ts +260 -0
- package/src/ts/examples/ZScoreNormalize/test-state.ts +277 -0
- package/src/ts/examples/ZScoreNormalize/test-streaming.ts +306 -0
- package/src/ts/examples/advanced-dsp-examples.ts +397 -0
- package/src/ts/examples/callbacks/advanced-router-features.ts +326 -0
- package/src/ts/examples/callbacks/benchmark-circular-buffer.ts +109 -0
- package/src/ts/examples/callbacks/monitoring-example.ts +265 -0
- package/src/ts/examples/callbacks/pipeline-callbacks-example.ts +137 -0
- package/src/ts/examples/callbacks/pooled-callbacks-example.ts +274 -0
- package/src/ts/examples/callbacks/priority-routing-example.ts +277 -0
- package/src/ts/examples/callbacks/production-topic-router.ts +214 -0
- package/src/ts/examples/callbacks/topic-based-logging.ts +161 -0
- package/src/ts/examples/chaining/test-chaining-redis.ts +113 -0
- package/src/ts/examples/chaining/test-chaining.ts +52 -0
- package/src/ts/examples/emg-features-example.ts +284 -0
- package/src/ts/examples/fft-example.ts +309 -0
- package/src/ts/examples/fft-examples.ts +349 -0
- package/src/ts/examples/filter-examples.ts +320 -0
- package/src/ts/examples/list-state-example.ts +131 -0
- package/src/ts/examples/logger-example.ts +91 -0
- package/src/ts/examples/notch-filter-examples.ts +243 -0
- package/src/ts/examples/phase5/drift-detection-example.ts +290 -0
- package/src/ts/examples/phase6-7/production-observability.ts +476 -0
- package/src/ts/examples/phase6-7/redis-timeseries-integration.ts +446 -0
- package/src/ts/examples/redis/redis-example.ts +202 -0
- package/src/ts/examples/redis-example.ts +202 -0
- package/src/ts/examples/simd-benchmark.ts +126 -0
- package/src/ts/examples/tap-debugging.ts +230 -0
- package/src/ts/examples/timeseries/comparison-example.ts +290 -0
- package/src/ts/examples/timeseries/iot-sensor-example.ts +143 -0
- package/src/ts/examples/timeseries/redis-streaming-example.ts +233 -0
- package/src/ts/examples/waveform-length-example.ts +139 -0
- package/src/ts/fft.ts +722 -0
- package/src/ts/filters.ts +1078 -0
- package/src/ts/index.ts +120 -0
- package/src/ts/types.ts +589 -0
- 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
|