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,277 @@
|
|
|
1
|
+
import { createDspPipeline } from "../../bindings.js";
|
|
2
|
+
|
|
3
|
+
console.log("Z-Score Normalize Filter - State Management Examples\n");
|
|
4
|
+
|
|
5
|
+
// =============================================================================
|
|
6
|
+
// Example 1: Batch Z-Score Normalization (Stateless)
|
|
7
|
+
// =============================================================================
|
|
8
|
+
console.log("1. Batch Z-Score Normalization (Stateless)");
|
|
9
|
+
|
|
10
|
+
const pipeline1 = createDspPipeline();
|
|
11
|
+
pipeline1.ZScoreNormalize({ mode: "batch" });
|
|
12
|
+
|
|
13
|
+
const input1 = new Float32Array([10, 20, 30, 40, 50]);
|
|
14
|
+
const output1 = await pipeline1.process(input1, {
|
|
15
|
+
sampleRate: 1000,
|
|
16
|
+
channels: 1,
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
console.log(` Input: [${input1.join(", ")}]`);
|
|
20
|
+
console.log(` Mean: 30, Std Dev: ~14.14`);
|
|
21
|
+
console.log(
|
|
22
|
+
` Output (normalized): [${Array.from(output1)
|
|
23
|
+
.map((v) => v.toFixed(3))
|
|
24
|
+
.join(", ")}]`
|
|
25
|
+
);
|
|
26
|
+
console.log(
|
|
27
|
+
` Mean after normalization: ${(
|
|
28
|
+
output1.reduce((s, v) => s + v, 0) / output1.length
|
|
29
|
+
).toFixed(6)}`
|
|
30
|
+
);
|
|
31
|
+
console.log(
|
|
32
|
+
` Variance after normalization: ${(
|
|
33
|
+
output1.reduce((s, v) => s + v * v, 0) / output1.length
|
|
34
|
+
).toFixed(6)}`
|
|
35
|
+
);
|
|
36
|
+
console.log("");
|
|
37
|
+
|
|
38
|
+
// =============================================================================
|
|
39
|
+
// Example 2: Moving Z-Score Normalization (Stateful)
|
|
40
|
+
// =============================================================================
|
|
41
|
+
console.log("2. Moving Z-Score Normalization (Stateful)");
|
|
42
|
+
|
|
43
|
+
const pipeline2 = createDspPipeline();
|
|
44
|
+
pipeline2.ZScoreNormalize({ mode: "moving", windowSize: 3 });
|
|
45
|
+
|
|
46
|
+
const input2 = new Float32Array([1, 2, 3, 4, 5]);
|
|
47
|
+
const output2 = await pipeline2.process(input2, {
|
|
48
|
+
sampleRate: 1000,
|
|
49
|
+
channels: 1,
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
console.log(` Input: [${input2.join(", ")}]`);
|
|
53
|
+
console.log(` Output (sliding window):`);
|
|
54
|
+
console.log(` [1] -> z-score: ${output2[0].toFixed(3)} (mean=1, stddev=0)`);
|
|
55
|
+
console.log(
|
|
56
|
+
` [1,2] -> z-score: ${output2[1].toFixed(3)} (mean=1.5, stddev=0.5)`
|
|
57
|
+
);
|
|
58
|
+
console.log(
|
|
59
|
+
` [1,2,3] -> z-score: ${output2[2].toFixed(3)} (mean=2, stddev≈0.816)`
|
|
60
|
+
);
|
|
61
|
+
console.log(
|
|
62
|
+
` [2,3,4] -> z-score: ${output2[3].toFixed(3)} (mean=3, stddev≈0.816)`
|
|
63
|
+
);
|
|
64
|
+
console.log(
|
|
65
|
+
` [3,4,5] -> z-score: ${output2[4].toFixed(3)} (mean=4, stddev≈0.816)`
|
|
66
|
+
);
|
|
67
|
+
console.log("");
|
|
68
|
+
|
|
69
|
+
// =============================================================================
|
|
70
|
+
// Example 3: Save and Restore State
|
|
71
|
+
// =============================================================================
|
|
72
|
+
console.log("3. Save and Restore State");
|
|
73
|
+
|
|
74
|
+
const pipeline3 = createDspPipeline();
|
|
75
|
+
pipeline3.ZScoreNormalize({ mode: "moving", windowSize: 5 });
|
|
76
|
+
|
|
77
|
+
// Build up state
|
|
78
|
+
const initialData = new Float32Array([10, 15, 20, 25, 30]);
|
|
79
|
+
await pipeline3.process(initialData, { sampleRate: 1000, channels: 1 });
|
|
80
|
+
|
|
81
|
+
// Save state
|
|
82
|
+
const stateJson = await pipeline3.saveState();
|
|
83
|
+
const state = JSON.parse(stateJson);
|
|
84
|
+
|
|
85
|
+
console.log(` Saved state:`);
|
|
86
|
+
console.log(` Mode: ${state.stages[0].state.mode}`);
|
|
87
|
+
console.log(` Window size: ${state.stages[0].state.windowSize}`);
|
|
88
|
+
console.log(
|
|
89
|
+
` Buffer: [${state.stages[0].state.channels[0].buffer.join(", ")}]`
|
|
90
|
+
);
|
|
91
|
+
console.log(` Running sum: ${state.stages[0].state.channels[0].runningSum}`);
|
|
92
|
+
console.log(
|
|
93
|
+
` Running sum of squares: ${state.stages[0].state.channels[0].runningSumOfSquares}`
|
|
94
|
+
);
|
|
95
|
+
|
|
96
|
+
// Restore state in a new pipeline
|
|
97
|
+
const pipeline3b = createDspPipeline();
|
|
98
|
+
pipeline3b.ZScoreNormalize({ mode: "moving", windowSize: 5 });
|
|
99
|
+
await pipeline3b.loadState(stateJson);
|
|
100
|
+
|
|
101
|
+
console.log(` State restored!`);
|
|
102
|
+
|
|
103
|
+
// Continue processing with restored state
|
|
104
|
+
const continuedData = new Float32Array([35, 40, 45]);
|
|
105
|
+
const continuedOutput = await pipeline3b.process(continuedData, {
|
|
106
|
+
sampleRate: 1000,
|
|
107
|
+
channels: 1,
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
console.log(` Continued with [${continuedData.join(", ")}]`);
|
|
111
|
+
console.log(
|
|
112
|
+
` Output: [${Array.from(continuedOutput)
|
|
113
|
+
.map((v) => v.toFixed(3))
|
|
114
|
+
.join(", ")}]`
|
|
115
|
+
);
|
|
116
|
+
console.log("");
|
|
117
|
+
|
|
118
|
+
// =============================================================================
|
|
119
|
+
// Example 4: Clear State (Reset)
|
|
120
|
+
// =============================================================================
|
|
121
|
+
console.log("4. Clear State (Reset)");
|
|
122
|
+
|
|
123
|
+
const pipeline4 = createDspPipeline();
|
|
124
|
+
pipeline4.ZScoreNormalize({ mode: "moving", windowSize: 3 });
|
|
125
|
+
|
|
126
|
+
// Process some data
|
|
127
|
+
await pipeline4.process(new Float32Array([100, 200, 300]), {
|
|
128
|
+
sampleRate: 1000,
|
|
129
|
+
channels: 1,
|
|
130
|
+
});
|
|
131
|
+
|
|
132
|
+
// Clear state
|
|
133
|
+
pipeline4.clearState();
|
|
134
|
+
console.log(` State cleared!`);
|
|
135
|
+
|
|
136
|
+
// Process new data (should start fresh)
|
|
137
|
+
const resetInput = new Float32Array([1, 2, 3]);
|
|
138
|
+
const resetOutput = await pipeline4.process(resetInput, {
|
|
139
|
+
sampleRate: 1000,
|
|
140
|
+
channels: 1,
|
|
141
|
+
});
|
|
142
|
+
|
|
143
|
+
console.log(` After reset, input [${resetInput.join(", ")}]:`);
|
|
144
|
+
console.log(
|
|
145
|
+
` Output: [${Array.from(resetOutput)
|
|
146
|
+
.map((v) => v.toFixed(3))
|
|
147
|
+
.join(", ")}]`
|
|
148
|
+
);
|
|
149
|
+
console.log(` (Same as if processing first time)`);
|
|
150
|
+
console.log("");
|
|
151
|
+
|
|
152
|
+
// =============================================================================
|
|
153
|
+
// Example 5: Batch vs Moving Comparison
|
|
154
|
+
// =============================================================================
|
|
155
|
+
console.log("5. Batch vs Moving Comparison");
|
|
156
|
+
|
|
157
|
+
const inputData = new Float32Array([10, 20, 30, 40, 50]);
|
|
158
|
+
|
|
159
|
+
// Batch mode
|
|
160
|
+
const batchPipeline = createDspPipeline();
|
|
161
|
+
batchPipeline.ZScoreNormalize({ mode: "batch" });
|
|
162
|
+
const batchOutput = await batchPipeline.process(inputData.slice(), {
|
|
163
|
+
sampleRate: 1000,
|
|
164
|
+
channels: 1,
|
|
165
|
+
});
|
|
166
|
+
|
|
167
|
+
// Moving mode
|
|
168
|
+
const movingPipeline = createDspPipeline();
|
|
169
|
+
movingPipeline.ZScoreNormalize({ mode: "moving", windowSize: 5 });
|
|
170
|
+
const movingOutput = await movingPipeline.process(inputData.slice(), {
|
|
171
|
+
sampleRate: 1000,
|
|
172
|
+
channels: 1,
|
|
173
|
+
});
|
|
174
|
+
|
|
175
|
+
console.log(` Input: [${inputData.join(", ")}]`);
|
|
176
|
+
console.log(
|
|
177
|
+
` Batch (global normalization): [${Array.from(batchOutput)
|
|
178
|
+
.map((v) => v.toFixed(3))
|
|
179
|
+
.join(", ")}]`
|
|
180
|
+
);
|
|
181
|
+
console.log(
|
|
182
|
+
` Moving (evolving window): [${Array.from(movingOutput)
|
|
183
|
+
.map((v) => v.toFixed(3))
|
|
184
|
+
.join(", ")}]`
|
|
185
|
+
);
|
|
186
|
+
console.log("");
|
|
187
|
+
console.log(` Batch: All samples normalized using entire dataset statistics`);
|
|
188
|
+
console.log(` Moving: Each sample normalized using local window statistics`);
|
|
189
|
+
console.log("");
|
|
190
|
+
|
|
191
|
+
// =============================================================================
|
|
192
|
+
// Example 6: Multi-Channel State Management
|
|
193
|
+
// =============================================================================
|
|
194
|
+
console.log("6. Multi-Channel State Management");
|
|
195
|
+
|
|
196
|
+
const pipeline6 = createDspPipeline();
|
|
197
|
+
pipeline6.ZScoreNormalize({ mode: "moving", windowSize: 3 });
|
|
198
|
+
|
|
199
|
+
// 2 channels, 5 samples per channel (interleaved)
|
|
200
|
+
// Channel 0: [1, 2, 3, 4, 5]
|
|
201
|
+
// Channel 1: [100, 200, 300, 400, 500]
|
|
202
|
+
const multiChannelInput = new Float32Array([
|
|
203
|
+
1, 100, 2, 200, 3, 300, 4, 400, 5, 500,
|
|
204
|
+
]);
|
|
205
|
+
|
|
206
|
+
await pipeline6.process(multiChannelInput, {
|
|
207
|
+
sampleRate: 1000,
|
|
208
|
+
channels: 2,
|
|
209
|
+
});
|
|
210
|
+
|
|
211
|
+
const state6 = JSON.parse(await pipeline6.saveState());
|
|
212
|
+
|
|
213
|
+
console.log(` 2-channel processing:`);
|
|
214
|
+
console.log(
|
|
215
|
+
` Channel 0 buffer: [${state6.stages[0].state.channels[0].buffer.join(
|
|
216
|
+
", "
|
|
217
|
+
)}]`
|
|
218
|
+
);
|
|
219
|
+
console.log(
|
|
220
|
+
` Channel 1 buffer: [${state6.stages[0].state.channels[1].buffer.join(
|
|
221
|
+
", "
|
|
222
|
+
)}]`
|
|
223
|
+
);
|
|
224
|
+
console.log(` (Each channel maintains independent state)`);
|
|
225
|
+
console.log("");
|
|
226
|
+
|
|
227
|
+
// =============================================================================
|
|
228
|
+
// Example 7: Custom Epsilon for Near-Constant Signals
|
|
229
|
+
// =============================================================================
|
|
230
|
+
console.log("7. Custom Epsilon for Near-Constant Signals");
|
|
231
|
+
|
|
232
|
+
const pipeline7a = createDspPipeline();
|
|
233
|
+
pipeline7a.ZScoreNormalize({ mode: "batch", epsilon: 1e-6 }); // Default
|
|
234
|
+
|
|
235
|
+
const pipeline7b = createDspPipeline();
|
|
236
|
+
pipeline7b.ZScoreNormalize({ mode: "batch", epsilon: 0.1 }); // Larger epsilon
|
|
237
|
+
|
|
238
|
+
// Nearly constant signal
|
|
239
|
+
const nearConstant = new Float32Array([5.0, 5.001, 4.999, 5.0, 5.001]);
|
|
240
|
+
|
|
241
|
+
const output7a = await pipeline7a.process(nearConstant.slice(), {
|
|
242
|
+
sampleRate: 1000,
|
|
243
|
+
channels: 1,
|
|
244
|
+
});
|
|
245
|
+
|
|
246
|
+
const output7b = await pipeline7b.process(nearConstant.slice(), {
|
|
247
|
+
sampleRate: 1000,
|
|
248
|
+
channels: 1,
|
|
249
|
+
});
|
|
250
|
+
|
|
251
|
+
console.log(` Input (nearly constant): [${nearConstant.join(", ")}]`);
|
|
252
|
+
console.log(
|
|
253
|
+
` Default epsilon (1e-6): [${Array.from(output7a)
|
|
254
|
+
.map((v) => v.toFixed(3))
|
|
255
|
+
.join(", ")}]`
|
|
256
|
+
);
|
|
257
|
+
console.log(
|
|
258
|
+
` Large epsilon (0.1): [${Array.from(output7b)
|
|
259
|
+
.map((v) => v.toFixed(3))
|
|
260
|
+
.join(", ")}]`
|
|
261
|
+
);
|
|
262
|
+
console.log("");
|
|
263
|
+
|
|
264
|
+
console.log("Key Takeaways:");
|
|
265
|
+
console.log(
|
|
266
|
+
" - Batch mode: Stateless, normalizes using global statistics (mean=0, stddev=1)"
|
|
267
|
+
);
|
|
268
|
+
console.log(
|
|
269
|
+
" - Moving mode: Stateful, normalizes using local window statistics"
|
|
270
|
+
);
|
|
271
|
+
console.log(
|
|
272
|
+
" - State includes: circular buffer, running sum, running sum of squares"
|
|
273
|
+
);
|
|
274
|
+
console.log(
|
|
275
|
+
" - Each channel has independent state for multi-channel processing"
|
|
276
|
+
);
|
|
277
|
+
console.log(" - Epsilon prevents division by zero when stddev is near 0");
|
|
@@ -0,0 +1,306 @@
|
|
|
1
|
+
import { createDspPipeline } from "../../bindings.js";
|
|
2
|
+
|
|
3
|
+
console.log("Z-Score Normalize Filter - Streaming Examples\n");
|
|
4
|
+
|
|
5
|
+
// =============================================================================
|
|
6
|
+
// Example 1: Batch Normalization for Data Preprocessing
|
|
7
|
+
// =============================================================================
|
|
8
|
+
console.log("1. Batch Normalization for Data Preprocessing");
|
|
9
|
+
|
|
10
|
+
const pipeline1 = createDspPipeline();
|
|
11
|
+
pipeline1.ZScoreNormalize({ mode: "batch" });
|
|
12
|
+
|
|
13
|
+
// Simulate processing chunks of sensor data before machine learning
|
|
14
|
+
const chunks = [
|
|
15
|
+
new Float32Array([23.5, 24.1, 23.8, 24.3, 23.9]), // Temperature readings (°C)
|
|
16
|
+
new Float32Array([100, 102, 98, 101, 99]), // Pressure readings (kPa)
|
|
17
|
+
new Float32Array([5.2, 5.5, 5.1, 5.4, 5.3]), // Flow rate (L/min)
|
|
18
|
+
];
|
|
19
|
+
|
|
20
|
+
console.log(" Normalizing sensor data chunks for ML preprocessing:");
|
|
21
|
+
for (let i = 0; i < chunks.length; i++) {
|
|
22
|
+
const output = await pipeline1.process(chunks[i].slice(), {
|
|
23
|
+
sampleRate: 100,
|
|
24
|
+
channels: 1,
|
|
25
|
+
});
|
|
26
|
+
const mean = output.reduce((s, v) => s + v, 0) / output.length;
|
|
27
|
+
const variance = output.reduce((s, v) => s + v * v, 0) / output.length;
|
|
28
|
+
console.log(
|
|
29
|
+
` Chunk ${i + 1}: mean=${mean.toFixed(6)}, variance=${variance.toFixed(
|
|
30
|
+
6
|
|
31
|
+
)} → NORMALIZED`
|
|
32
|
+
);
|
|
33
|
+
}
|
|
34
|
+
console.log("");
|
|
35
|
+
|
|
36
|
+
// =============================================================================
|
|
37
|
+
// Example 2: Real-Time Anomaly Detection with Moving Z-Score
|
|
38
|
+
// =============================================================================
|
|
39
|
+
console.log("2. Real-Time Anomaly Detection with Moving Z-Score");
|
|
40
|
+
|
|
41
|
+
const pipeline2 = createDspPipeline();
|
|
42
|
+
pipeline2.ZScoreNormalize({ mode: "moving", windowSize: 50 });
|
|
43
|
+
|
|
44
|
+
// Simulate streaming temperature data with an anomaly
|
|
45
|
+
const normalData = new Float32Array(40)
|
|
46
|
+
.fill(0)
|
|
47
|
+
.map(() => 20 + Math.random() * 2); // Normal: 20-22°C
|
|
48
|
+
const anomalyData = new Float32Array(10).fill(0).map(() => 30 + Math.random()); // Anomaly: 30-31°C
|
|
49
|
+
const recoveryData = new Float32Array(20)
|
|
50
|
+
.fill(0)
|
|
51
|
+
.map(() => 20 + Math.random() * 2); // Back to normal
|
|
52
|
+
|
|
53
|
+
const streamData = new Float32Array([
|
|
54
|
+
...normalData,
|
|
55
|
+
...anomalyData,
|
|
56
|
+
...recoveryData,
|
|
57
|
+
]);
|
|
58
|
+
|
|
59
|
+
const zScores = await pipeline2.process(streamData, {
|
|
60
|
+
sampleRate: 10,
|
|
61
|
+
channels: 1,
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
let anomalyCount = 0;
|
|
65
|
+
const anomalyThreshold = 3.0; // Standard threshold for outlier detection
|
|
66
|
+
|
|
67
|
+
console.log(" Monitoring temperature stream for anomalies (z-score > 3.0):");
|
|
68
|
+
for (let i = 0; i < zScores.length; i++) {
|
|
69
|
+
if (Math.abs(zScores[i]) > anomalyThreshold) {
|
|
70
|
+
if (anomalyCount === 0) {
|
|
71
|
+
console.log(
|
|
72
|
+
` 🚨 ANOMALY DETECTED at sample ${i}: z-score = ${zScores[i].toFixed(
|
|
73
|
+
2
|
|
74
|
+
)}`
|
|
75
|
+
);
|
|
76
|
+
}
|
|
77
|
+
anomalyCount++;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
console.log(` Total anomalies detected: ${anomalyCount}`);
|
|
81
|
+
console.log("");
|
|
82
|
+
|
|
83
|
+
// =============================================================================
|
|
84
|
+
// Example 3: Multi-Channel EEG Signal Normalization
|
|
85
|
+
// =============================================================================
|
|
86
|
+
console.log("3. Multi-Channel EEG Signal Normalization");
|
|
87
|
+
|
|
88
|
+
const pipeline3 = createDspPipeline();
|
|
89
|
+
pipeline3.ZScoreNormalize({ mode: "moving", windowSize: 100 });
|
|
90
|
+
|
|
91
|
+
// Simulate 4 EEG channels with different amplitudes
|
|
92
|
+
const numSamples = 200;
|
|
93
|
+
const numChannels = 4;
|
|
94
|
+
const eegData = new Float32Array(numSamples * numChannels);
|
|
95
|
+
|
|
96
|
+
for (let i = 0; i < numSamples; i++) {
|
|
97
|
+
eegData[i * numChannels + 0] = Math.sin(i * 0.1) * 50; // Channel 0: 50µV amplitude
|
|
98
|
+
eegData[i * numChannels + 1] = Math.sin(i * 0.15) * 100; // Channel 1: 100µV amplitude
|
|
99
|
+
eegData[i * numChannels + 2] = Math.sin(i * 0.2) * 25; // Channel 2: 25µV amplitude
|
|
100
|
+
eegData[i * numChannels + 3] = Math.sin(i * 0.25) * 75; // Channel 3: 75µV amplitude
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
const normalizedEEG = await pipeline3.process(eegData, {
|
|
104
|
+
sampleRate: 256,
|
|
105
|
+
channels: numChannels,
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
// Extract last 20 samples of each channel to check normalization
|
|
109
|
+
const extractChannel = (data: Float32Array, ch: number, numCh: number) => {
|
|
110
|
+
const result = [];
|
|
111
|
+
for (let i = ch; i < data.length; i += numCh) {
|
|
112
|
+
result.push(data[i]);
|
|
113
|
+
}
|
|
114
|
+
return result.slice(-20);
|
|
115
|
+
};
|
|
116
|
+
|
|
117
|
+
console.log(" Normalized EEG channels (last 20 samples):");
|
|
118
|
+
for (let ch = 0; ch < numChannels; ch++) {
|
|
119
|
+
const samples = extractChannel(normalizedEEG, ch, numChannels);
|
|
120
|
+
const mean = samples.reduce((s, v) => s + v, 0) / samples.length;
|
|
121
|
+
const variance = samples.reduce((s, v) => s + v * v, 0) / samples.length;
|
|
122
|
+
console.log(
|
|
123
|
+
` Channel ${ch}: mean=${mean.toFixed(3)}, variance=${variance.toFixed(
|
|
124
|
+
3
|
|
125
|
+
)}`
|
|
126
|
+
);
|
|
127
|
+
}
|
|
128
|
+
console.log("");
|
|
129
|
+
|
|
130
|
+
// =============================================================================
|
|
131
|
+
// Example 4: Interrupted Processing with State Recovery
|
|
132
|
+
// =============================================================================
|
|
133
|
+
console.log("4. Interrupted Processing with State Recovery");
|
|
134
|
+
|
|
135
|
+
const pipeline4 = createDspPipeline();
|
|
136
|
+
pipeline4.ZScoreNormalize({ mode: "moving", windowSize: 30 });
|
|
137
|
+
|
|
138
|
+
// Process first chunk
|
|
139
|
+
const chunk1 = new Float32Array(50).fill(0).map(() => 100 + Math.random() * 20);
|
|
140
|
+
await pipeline4.process(chunk1, { sampleRate: 1000, channels: 1 });
|
|
141
|
+
|
|
142
|
+
console.log(" Processing stream...");
|
|
143
|
+
|
|
144
|
+
// Save state (simulating service restart or crash recovery)
|
|
145
|
+
const savedState = await pipeline4.saveState();
|
|
146
|
+
console.log(" State saved (simulating service restart)");
|
|
147
|
+
|
|
148
|
+
// Create new pipeline and restore state
|
|
149
|
+
const pipeline4b = createDspPipeline();
|
|
150
|
+
pipeline4b.ZScoreNormalize({ mode: "moving", windowSize: 30 });
|
|
151
|
+
await pipeline4b.loadState(savedState);
|
|
152
|
+
|
|
153
|
+
console.log(" State restored!");
|
|
154
|
+
|
|
155
|
+
// Continue processing
|
|
156
|
+
const chunk2 = new Float32Array(30).fill(0).map(() => 100 + Math.random() * 20);
|
|
157
|
+
const output = await pipeline4b.process(chunk2, {
|
|
158
|
+
sampleRate: 1000,
|
|
159
|
+
channels: 1,
|
|
160
|
+
});
|
|
161
|
+
|
|
162
|
+
console.log(` Resumed processing: ${output.length} samples processed`);
|
|
163
|
+
console.log(` (Seamless continuation from saved state)`);
|
|
164
|
+
console.log("");
|
|
165
|
+
|
|
166
|
+
// =============================================================================
|
|
167
|
+
// Example 5: Feature Extraction Pipeline (Rectify → Z-Score)
|
|
168
|
+
// =============================================================================
|
|
169
|
+
console.log("5. Feature Extraction Pipeline (Rectify → Z-Score)");
|
|
170
|
+
|
|
171
|
+
const pipeline5 = createDspPipeline();
|
|
172
|
+
pipeline5.Rectify({ mode: "full" }).ZScoreNormalize({
|
|
173
|
+
mode: "moving",
|
|
174
|
+
windowSize: 50,
|
|
175
|
+
});
|
|
176
|
+
|
|
177
|
+
// Generate bipolar signal with noise
|
|
178
|
+
const signalLength = 200;
|
|
179
|
+
const rawSignal = new Float32Array(signalLength);
|
|
180
|
+
for (let i = 0; i < signalLength; i++) {
|
|
181
|
+
rawSignal[i] = Math.sin(i * 0.1) * 10 + (Math.random() - 0.5) * 5;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
const features = await pipeline5.process(rawSignal, {
|
|
185
|
+
sampleRate: 100,
|
|
186
|
+
channels: 1,
|
|
187
|
+
});
|
|
188
|
+
|
|
189
|
+
// Calculate feature statistics
|
|
190
|
+
const mean = features.reduce((s, v) => s + v, 0) / features.length;
|
|
191
|
+
const variance = features.reduce((s, v) => s + v * v, 0) / features.length;
|
|
192
|
+
const recentMean = features.slice(-20).reduce((s, v) => s + v, 0) / 20;
|
|
193
|
+
|
|
194
|
+
console.log(` Input signal: ${signalLength} samples (bipolar with noise)`);
|
|
195
|
+
console.log(` After Rectify: All positive values`);
|
|
196
|
+
console.log(` After Z-Score: Normalized features`);
|
|
197
|
+
console.log(` Overall mean: ${mean.toFixed(3)}`);
|
|
198
|
+
console.log(` Overall variance: ${variance.toFixed(3)}`);
|
|
199
|
+
console.log(` Recent avg z-score: ${recentMean.toFixed(3)}`);
|
|
200
|
+
console.log(` (Ready for ML feature extraction)`);
|
|
201
|
+
console.log("");
|
|
202
|
+
|
|
203
|
+
// =============================================================================
|
|
204
|
+
// Example 6: Adaptive Threshold Alerting
|
|
205
|
+
// =============================================================================
|
|
206
|
+
console.log("6. Adaptive Threshold Alerting");
|
|
207
|
+
|
|
208
|
+
const pipeline6 = createDspPipeline();
|
|
209
|
+
pipeline6.ZScoreNormalize({ mode: "moving", windowSize: 50 });
|
|
210
|
+
|
|
211
|
+
// Simulate streaming data with gradual drift
|
|
212
|
+
const generateChunk = (baseline: number, drift: number) => {
|
|
213
|
+
return new Float32Array(100)
|
|
214
|
+
.fill(0)
|
|
215
|
+
.map(() => baseline + drift + (Math.random() - 0.5) * 5);
|
|
216
|
+
};
|
|
217
|
+
|
|
218
|
+
const chunks6 = [
|
|
219
|
+
generateChunk(100, 0), // Baseline
|
|
220
|
+
generateChunk(100, 5), // Small drift
|
|
221
|
+
generateChunk(100, 20), // Significant drift
|
|
222
|
+
];
|
|
223
|
+
|
|
224
|
+
const alertThreshold = 2.5;
|
|
225
|
+
|
|
226
|
+
console.log(` Monitoring for z-score > ${alertThreshold}:`);
|
|
227
|
+
for (let i = 0; i < chunks6.length; i++) {
|
|
228
|
+
const zScores = await pipeline6.process(chunks6[i], {
|
|
229
|
+
sampleRate: 100,
|
|
230
|
+
channels: 1,
|
|
231
|
+
});
|
|
232
|
+
|
|
233
|
+
const alertCount = zScores.filter((z) => Math.abs(z) > alertThreshold).length;
|
|
234
|
+
|
|
235
|
+
if (alertCount > 10) {
|
|
236
|
+
console.log(
|
|
237
|
+
` Chunk ${i + 1}: 🚨 ALERT - ${alertCount} samples exceeded threshold`
|
|
238
|
+
);
|
|
239
|
+
} else {
|
|
240
|
+
console.log(` Chunk ${i + 1}: ✓ OK - drift within normal range`);
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
console.log("");
|
|
244
|
+
|
|
245
|
+
// =============================================================================
|
|
246
|
+
// Example 7: Streaming Data Standardization for Neural Network
|
|
247
|
+
// =============================================================================
|
|
248
|
+
console.log("7. Streaming Data Standardization for Neural Network");
|
|
249
|
+
|
|
250
|
+
const pipeline7 = createDspPipeline();
|
|
251
|
+
pipeline7.ZScoreNormalize({ mode: "moving", windowSize: 100 });
|
|
252
|
+
|
|
253
|
+
// Simulate streaming accelerometer data (3 axes, interleaved)
|
|
254
|
+
const streamLength = 300; // 100 samples per axis
|
|
255
|
+
const accelData = new Float32Array(streamLength);
|
|
256
|
+
|
|
257
|
+
for (let i = 0; i < streamLength / 3; i++) {
|
|
258
|
+
accelData[i * 3 + 0] = Math.sin(i * 0.1) * 2 + 9.8; // X-axis (with gravity)
|
|
259
|
+
accelData[i * 3 + 1] = Math.cos(i * 0.1) * 1.5; // Y-axis
|
|
260
|
+
accelData[i * 3 + 2] = Math.sin(i * 0.15) * 1.0; // Z-axis
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
const normalizedAccel = await pipeline7.process(accelData, {
|
|
264
|
+
sampleRate: 50,
|
|
265
|
+
channels: 3,
|
|
266
|
+
});
|
|
267
|
+
|
|
268
|
+
// Verify normalization for each axis
|
|
269
|
+
const axes = ["X", "Y", "Z"];
|
|
270
|
+
console.log(" Accelerometer data normalized for neural network:");
|
|
271
|
+
for (let axis = 0; axis < 3; axis++) {
|
|
272
|
+
const axisData = [];
|
|
273
|
+
for (let i = axis; i < normalizedAccel.length; i += 3) {
|
|
274
|
+
axisData.push(normalizedAccel[i]);
|
|
275
|
+
}
|
|
276
|
+
const mean = axisData.reduce((s, v) => s + v, 0) / axisData.length;
|
|
277
|
+
const variance = axisData.reduce((s, v) => s + v * v, 0) / axisData.length;
|
|
278
|
+
|
|
279
|
+
console.log(
|
|
280
|
+
` ${axes[axis]}-axis: mean=${mean.toFixed(
|
|
281
|
+
4
|
|
282
|
+
)}, variance=${variance.toFixed(4)} → READY`
|
|
283
|
+
);
|
|
284
|
+
}
|
|
285
|
+
console.log("");
|
|
286
|
+
|
|
287
|
+
console.log("Streaming Use Cases:");
|
|
288
|
+
console.log(
|
|
289
|
+
" - Data preprocessing: Normalize features before machine learning"
|
|
290
|
+
);
|
|
291
|
+
console.log(
|
|
292
|
+
" - Anomaly detection: Identify outliers using z-score thresholds (±3σ)"
|
|
293
|
+
);
|
|
294
|
+
console.log(
|
|
295
|
+
" - Multi-channel normalization: EEG, EMG, accelerometer standardization"
|
|
296
|
+
);
|
|
297
|
+
console.log(" - Crash recovery: Maintain state across service restarts");
|
|
298
|
+
console.log(
|
|
299
|
+
" - Feature extraction: Combine with other filters (Rectify, RMS, etc.)"
|
|
300
|
+
);
|
|
301
|
+
console.log(
|
|
302
|
+
" - Adaptive alerting: Detect drift and anomalies in streaming data"
|
|
303
|
+
);
|
|
304
|
+
console.log(
|
|
305
|
+
" - Neural network preprocessing: Standardize input features for deep learning"
|
|
306
|
+
);
|