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,195 @@
|
|
|
1
|
+
import { createDspPipeline } from "../../index.js";
|
|
2
|
+
|
|
3
|
+
console.log("Variance Filter - State Management Examples\n");
|
|
4
|
+
|
|
5
|
+
// Example 1: Batch variance (stateless)
|
|
6
|
+
console.log("1. Batch Variance (Stateless)");
|
|
7
|
+
{
|
|
8
|
+
const pipeline = createDspPipeline().Variance({ mode: "batch" });
|
|
9
|
+
|
|
10
|
+
const input = new Float32Array([1, 2, 3, 4, 5]);
|
|
11
|
+
const output = await pipeline.process(input, {
|
|
12
|
+
sampleRate: 1000,
|
|
13
|
+
channels: 1,
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
console.log(` Input: [${Array.from(input).join(", ")}]`);
|
|
17
|
+
console.log(` Output (all same): ${output[0].toFixed(3)}`);
|
|
18
|
+
console.log(` Expected variance: 2.0 (spread around mean of 3)`);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
// Example 2: Moving variance (stateful)
|
|
22
|
+
console.log("\n2. Moving Variance (Stateful)");
|
|
23
|
+
{
|
|
24
|
+
const pipeline = createDspPipeline().Variance({
|
|
25
|
+
mode: "moving",
|
|
26
|
+
windowSize: 3,
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
const input = new Float32Array([1, 2, 3, 4, 5]);
|
|
30
|
+
const output = await pipeline.process(input, {
|
|
31
|
+
sampleRate: 1000,
|
|
32
|
+
channels: 1,
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
console.log(` Input: [${Array.from(input).join(", ")}]`);
|
|
36
|
+
console.log(` Output (sliding window):`);
|
|
37
|
+
console.log(` [1] -> variance: ${output[0].toFixed(3)}`);
|
|
38
|
+
console.log(` [1,2] -> variance: ${output[1].toFixed(3)}`);
|
|
39
|
+
console.log(` [1,2,3] -> variance: ${output[2].toFixed(3)}`);
|
|
40
|
+
console.log(` [2,3,4] -> variance: ${output[3].toFixed(3)}`);
|
|
41
|
+
console.log(` [3,4,5] -> variance: ${output[4].toFixed(3)}`);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
// Example 3: Save and restore state
|
|
45
|
+
console.log("\n3. Save and Restore State");
|
|
46
|
+
{
|
|
47
|
+
const pipeline = createDspPipeline().Variance({
|
|
48
|
+
mode: "moving",
|
|
49
|
+
windowSize: 5,
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
// Process first batch
|
|
53
|
+
const input1 = new Float32Array([1, 2, 3, 4, 5]);
|
|
54
|
+
await pipeline.process(input1, { sampleRate: 1000, channels: 1 });
|
|
55
|
+
|
|
56
|
+
// Save state
|
|
57
|
+
const stateJson = await pipeline.saveState();
|
|
58
|
+
const state = JSON.parse(stateJson);
|
|
59
|
+
|
|
60
|
+
console.log(" Saved state:");
|
|
61
|
+
console.log(` Mode: ${state.stages[0].state.mode}`);
|
|
62
|
+
console.log(` Window size: ${state.stages[0].state.windowSize}`);
|
|
63
|
+
console.log(
|
|
64
|
+
` Buffer: [${state.stages[0].state.channels[0].buffer.join(", ")}]`
|
|
65
|
+
);
|
|
66
|
+
console.log(
|
|
67
|
+
` Running sum: ${state.stages[0].state.channels[0].runningSum}`
|
|
68
|
+
);
|
|
69
|
+
|
|
70
|
+
// Create new pipeline and restore
|
|
71
|
+
const pipeline2 = createDspPipeline().Variance({
|
|
72
|
+
mode: "moving",
|
|
73
|
+
windowSize: 5,
|
|
74
|
+
});
|
|
75
|
+
await pipeline2.loadState(stateJson);
|
|
76
|
+
|
|
77
|
+
console.log(" State restored!");
|
|
78
|
+
|
|
79
|
+
// Continue processing
|
|
80
|
+
const input2 = new Float32Array([6, 7, 8]);
|
|
81
|
+
const output = await pipeline2.process(input2, {
|
|
82
|
+
sampleRate: 1000,
|
|
83
|
+
channels: 1,
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
console.log(` Continued with [6, 7, 8]`);
|
|
87
|
+
console.log(
|
|
88
|
+
` Output: [${Array.from(output)
|
|
89
|
+
.map((v) => v.toFixed(3))
|
|
90
|
+
.join(", ")}]`
|
|
91
|
+
);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
// Example 4: Clear state
|
|
95
|
+
console.log("\n4. Clear State (Reset)");
|
|
96
|
+
{
|
|
97
|
+
const pipeline = createDspPipeline().Variance({
|
|
98
|
+
mode: "moving",
|
|
99
|
+
windowSize: 3,
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
// Build up state
|
|
103
|
+
await pipeline.process(new Float32Array([10, 20, 30, 40, 50]), {
|
|
104
|
+
sampleRate: 1000,
|
|
105
|
+
channels: 1,
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
// Clear state
|
|
109
|
+
pipeline.clearState();
|
|
110
|
+
console.log(" State cleared!");
|
|
111
|
+
|
|
112
|
+
// Process new data - should start fresh
|
|
113
|
+
const input = new Float32Array([1, 2, 3]);
|
|
114
|
+
const output = await pipeline.process(input, {
|
|
115
|
+
sampleRate: 1000,
|
|
116
|
+
channels: 1,
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
console.log(` After reset, input [1, 2, 3]:`);
|
|
120
|
+
console.log(
|
|
121
|
+
` Output: [${Array.from(output)
|
|
122
|
+
.map((v) => v.toFixed(3))
|
|
123
|
+
.join(", ")}]`
|
|
124
|
+
);
|
|
125
|
+
console.log(` (Same as if processing first time)`);
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
// Example 5: Batch vs Moving comparison
|
|
129
|
+
console.log("\n5. Batch vs Moving Comparison");
|
|
130
|
+
{
|
|
131
|
+
const batchPipeline = createDspPipeline().Variance({ mode: "batch" });
|
|
132
|
+
const movingPipeline = createDspPipeline().Variance({
|
|
133
|
+
mode: "moving",
|
|
134
|
+
windowSize: 5,
|
|
135
|
+
});
|
|
136
|
+
|
|
137
|
+
const data = new Float32Array([1, 2, 3, 4, 5]);
|
|
138
|
+
|
|
139
|
+
const batchOutput = await batchPipeline.process(data.slice(), {
|
|
140
|
+
sampleRate: 1000,
|
|
141
|
+
channels: 1,
|
|
142
|
+
});
|
|
143
|
+
const movingOutput = await movingPipeline.process(data.slice(), {
|
|
144
|
+
sampleRate: 1000,
|
|
145
|
+
channels: 1,
|
|
146
|
+
});
|
|
147
|
+
|
|
148
|
+
console.log(` Input: [${Array.from(data).join(", ")}]`);
|
|
149
|
+
console.log(` Batch (all same): ${batchOutput[0].toFixed(3)}`);
|
|
150
|
+
console.log(
|
|
151
|
+
` Moving (evolving): [${Array.from(movingOutput)
|
|
152
|
+
.map((v) => v.toFixed(3))
|
|
153
|
+
.join(", ")}]`
|
|
154
|
+
);
|
|
155
|
+
console.log("\n Batch: Single variance for entire dataset");
|
|
156
|
+
console.log(" Moving: Variance evolves as window slides");
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
// Example 6: Multi-channel state
|
|
160
|
+
console.log("\n6. Multi-Channel State Management");
|
|
161
|
+
{
|
|
162
|
+
const pipeline = createDspPipeline().Variance({
|
|
163
|
+
mode: "moving",
|
|
164
|
+
windowSize: 3,
|
|
165
|
+
});
|
|
166
|
+
|
|
167
|
+
// 2-channel interleaved data
|
|
168
|
+
const input = new Float32Array([1, 10, 2, 20, 3, 30, 4, 40, 5, 50]);
|
|
169
|
+
await pipeline.process(input, { sampleRate: 1000, channels: 2 });
|
|
170
|
+
|
|
171
|
+
const state = JSON.parse(await pipeline.saveState());
|
|
172
|
+
|
|
173
|
+
console.log(" 2-channel processing:");
|
|
174
|
+
console.log(
|
|
175
|
+
` Channel 0 buffer: [${state.stages[0].state.channels[0].buffer.join(
|
|
176
|
+
", "
|
|
177
|
+
)}]`
|
|
178
|
+
);
|
|
179
|
+
console.log(
|
|
180
|
+
` Channel 1 buffer: [${state.stages[0].state.channels[1].buffer.join(
|
|
181
|
+
", "
|
|
182
|
+
)}]`
|
|
183
|
+
);
|
|
184
|
+
console.log(" (Each channel maintains independent state)");
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
console.log("\nKey Takeaways:");
|
|
188
|
+
console.log(" - Batch mode: Stateless, computes variance over entire batch");
|
|
189
|
+
console.log(" - Moving mode: Stateful, maintains sliding window");
|
|
190
|
+
console.log(
|
|
191
|
+
" - State includes: circular buffer, running sum, running sum of squares"
|
|
192
|
+
);
|
|
193
|
+
console.log(
|
|
194
|
+
" - Each channel has independent state for multi-channel processing"
|
|
195
|
+
);
|
|
@@ -0,0 +1,260 @@
|
|
|
1
|
+
import { createDspPipeline } from "../../index.js";
|
|
2
|
+
|
|
3
|
+
console.log("Variance Filter - Streaming Examples\n");
|
|
4
|
+
|
|
5
|
+
// Example 1: Batch variance for signal quality monitoring
|
|
6
|
+
console.log("1. Batch Variance for Signal Quality Monitoring");
|
|
7
|
+
{
|
|
8
|
+
const pipeline = createDspPipeline().Variance({ mode: "batch" });
|
|
9
|
+
|
|
10
|
+
console.log(" Monitoring signal stability across chunks:");
|
|
11
|
+
|
|
12
|
+
const chunks = [
|
|
13
|
+
new Float32Array([1, 1.1, 0.9, 1.05, 0.95]), // Stable signal
|
|
14
|
+
new Float32Array([5, 15, 25, 35, 45]), // Increasing signal
|
|
15
|
+
new Float32Array([50, 10, 60, 5, 55]), // Noisy signal
|
|
16
|
+
];
|
|
17
|
+
|
|
18
|
+
for (let i = 0; i < chunks.length; i++) {
|
|
19
|
+
const output = await pipeline.process(chunks[i].slice(), {
|
|
20
|
+
sampleRate: 1000,
|
|
21
|
+
channels: 1,
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
const variance = output[0];
|
|
25
|
+
const quality =
|
|
26
|
+
variance < 1 ? "STABLE" : variance < 100 ? "MODERATE" : "NOISY";
|
|
27
|
+
|
|
28
|
+
console.log(
|
|
29
|
+
` Chunk ${i + 1}: variance = ${variance.toFixed(2)} -> ${quality}`
|
|
30
|
+
);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
// Example 2: Moving variance for real-time variability detection
|
|
35
|
+
console.log("\n2. Moving Variance for Real-Time Variability Detection");
|
|
36
|
+
{
|
|
37
|
+
const pipeline = createDspPipeline().Variance({
|
|
38
|
+
mode: "moving",
|
|
39
|
+
windowSize: 10,
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
console.log(" Detecting variability changes in streaming data:");
|
|
43
|
+
|
|
44
|
+
// Simulate streaming sensor data with changing variability
|
|
45
|
+
const chunk1 = new Float32Array(20).map(
|
|
46
|
+
(_, i) => 100 + Math.sin(i * 0.1) * 2
|
|
47
|
+
); // Low variance
|
|
48
|
+
const chunk2 = new Float32Array(20).map(
|
|
49
|
+
(_, i) => 100 + Math.sin(i * 0.1) * 20
|
|
50
|
+
); // High variance
|
|
51
|
+
const chunk3 = new Float32Array(20).map(
|
|
52
|
+
(_, i) => 100 + Math.sin(i * 0.1) * 2
|
|
53
|
+
); // Back to low
|
|
54
|
+
|
|
55
|
+
const output1 = await pipeline.process(chunk1, {
|
|
56
|
+
sampleRate: 1000,
|
|
57
|
+
channels: 1,
|
|
58
|
+
});
|
|
59
|
+
const output2 = await pipeline.process(chunk2, {
|
|
60
|
+
sampleRate: 1000,
|
|
61
|
+
channels: 1,
|
|
62
|
+
});
|
|
63
|
+
const output3 = await pipeline.process(chunk3, {
|
|
64
|
+
sampleRate: 1000,
|
|
65
|
+
channels: 1,
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
console.log(
|
|
69
|
+
` Chunk 1 avg variance: ${(
|
|
70
|
+
output1.reduce((a, b) => a + b) / output1.length
|
|
71
|
+
).toFixed(2)}`
|
|
72
|
+
);
|
|
73
|
+
console.log(
|
|
74
|
+
` Chunk 2 avg variance: ${(
|
|
75
|
+
output2.reduce((a, b) => a + b) / output2.length
|
|
76
|
+
).toFixed(2)}`
|
|
77
|
+
);
|
|
78
|
+
console.log(
|
|
79
|
+
` Chunk 3 avg variance: ${(
|
|
80
|
+
output3.reduce((a, b) => a + b) / output3.length
|
|
81
|
+
).toFixed(2)}`
|
|
82
|
+
);
|
|
83
|
+
console.log(" (Variance adapts to signal characteristics)");
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
// Example 3: Multi-channel EMG processing with variance
|
|
87
|
+
console.log("\n3. Multi-Channel EMG Variance Monitoring");
|
|
88
|
+
{
|
|
89
|
+
const pipeline = createDspPipeline().Variance({
|
|
90
|
+
mode: "moving",
|
|
91
|
+
windowSize: 50,
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
// Simulate 4-channel EMG data
|
|
95
|
+
const generateEMG = (amplitude: number, length: number) => {
|
|
96
|
+
return new Float32Array(length).map(
|
|
97
|
+
() => (Math.random() - 0.5) * 2 * amplitude
|
|
98
|
+
);
|
|
99
|
+
};
|
|
100
|
+
|
|
101
|
+
// Channel 1: High activity, Channel 2: Low activity, etc.
|
|
102
|
+
const ch1 = generateEMG(100, 100);
|
|
103
|
+
const ch2 = generateEMG(20, 100);
|
|
104
|
+
const ch3 = generateEMG(60, 100);
|
|
105
|
+
const ch4 = generateEMG(30, 100);
|
|
106
|
+
|
|
107
|
+
// Interleave channels
|
|
108
|
+
const interleaved = new Float32Array(400);
|
|
109
|
+
for (let i = 0; i < 100; i++) {
|
|
110
|
+
interleaved[i * 4] = ch1[i];
|
|
111
|
+
interleaved[i * 4 + 1] = ch2[i];
|
|
112
|
+
interleaved[i * 4 + 2] = ch3[i];
|
|
113
|
+
interleaved[i * 4 + 3] = ch4[i];
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
const output = await pipeline.process(interleaved, {
|
|
117
|
+
sampleRate: 2000,
|
|
118
|
+
channels: 4,
|
|
119
|
+
});
|
|
120
|
+
|
|
121
|
+
// Calculate average variance per channel
|
|
122
|
+
const avgVariances = [0, 0, 0, 0];
|
|
123
|
+
for (let i = 0; i < output.length; i++) {
|
|
124
|
+
avgVariances[i % 4] += output[i];
|
|
125
|
+
}
|
|
126
|
+
avgVariances.forEach((sum, ch) => {
|
|
127
|
+
avgVariances[ch] = sum / (output.length / 4);
|
|
128
|
+
});
|
|
129
|
+
|
|
130
|
+
console.log(" Average variance per muscle channel:");
|
|
131
|
+
avgVariances.forEach((var_, ch) => {
|
|
132
|
+
const activity = var_ > 5000 ? "HIGH" : var_ > 2000 ? "MODERATE" : "LOW";
|
|
133
|
+
console.log(
|
|
134
|
+
` Channel ${ch}: ${var_.toFixed(0)} -> ${activity} activity`
|
|
135
|
+
);
|
|
136
|
+
});
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
// Example 4: Interrupted processing with state recovery
|
|
140
|
+
console.log("\n4. Interrupted Processing with State Recovery");
|
|
141
|
+
{
|
|
142
|
+
const pipeline = createDspPipeline().Variance({
|
|
143
|
+
mode: "moving",
|
|
144
|
+
windowSize: 20,
|
|
145
|
+
});
|
|
146
|
+
|
|
147
|
+
// Simulate streaming with interruption
|
|
148
|
+
console.log(" Processing stream...");
|
|
149
|
+
|
|
150
|
+
// Process first chunk
|
|
151
|
+
const chunk1 = new Float32Array(30).map((_, i) => Math.sin(i * 0.1) * 50);
|
|
152
|
+
await pipeline.process(chunk1, { sampleRate: 1000, channels: 1 });
|
|
153
|
+
|
|
154
|
+
// Save state before interruption
|
|
155
|
+
const savedState = await pipeline.saveState();
|
|
156
|
+
console.log(" State saved (simulating service restart)");
|
|
157
|
+
|
|
158
|
+
// Simulate restart - create new pipeline
|
|
159
|
+
const pipeline2 = createDspPipeline().Variance({
|
|
160
|
+
mode: "moving",
|
|
161
|
+
windowSize: 20,
|
|
162
|
+
});
|
|
163
|
+
await pipeline2.loadState(savedState);
|
|
164
|
+
console.log(" State restored!");
|
|
165
|
+
|
|
166
|
+
// Continue processing
|
|
167
|
+
const chunk2 = new Float32Array(30).map(
|
|
168
|
+
(_, i) => Math.sin((i + 30) * 0.1) * 50
|
|
169
|
+
);
|
|
170
|
+
const output = await pipeline2.process(chunk2, {
|
|
171
|
+
sampleRate: 1000,
|
|
172
|
+
channels: 1,
|
|
173
|
+
});
|
|
174
|
+
|
|
175
|
+
console.log(` Resumed processing: ${output.length} samples processed`);
|
|
176
|
+
console.log(" (Seamless continuation from saved state)");
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
// Example 5: Combining with other filters for feature extraction
|
|
180
|
+
console.log("\n5. Feature Extraction Pipeline (Rectify → Variance)");
|
|
181
|
+
{
|
|
182
|
+
const pipeline = createDspPipeline()
|
|
183
|
+
.Rectify({ mode: "full" })
|
|
184
|
+
.Variance({ mode: "moving", windowSize: 100 });
|
|
185
|
+
|
|
186
|
+
// Simulate biosignal with varying amplitude
|
|
187
|
+
const signal = new Float32Array(200).map((_, i) => {
|
|
188
|
+
const base = Math.sin(i * 0.05) * 100;
|
|
189
|
+
const noise = (Math.random() - 0.5) * 20;
|
|
190
|
+
return base + noise;
|
|
191
|
+
});
|
|
192
|
+
|
|
193
|
+
const output = await pipeline.process(signal, {
|
|
194
|
+
sampleRate: 1000,
|
|
195
|
+
channels: 1,
|
|
196
|
+
});
|
|
197
|
+
|
|
198
|
+
// Get last 10 variance values
|
|
199
|
+
const recentVariance = Array.from(output.slice(-10));
|
|
200
|
+
const avgVariance =
|
|
201
|
+
recentVariance.reduce((a, b) => a + b) / recentVariance.length;
|
|
202
|
+
|
|
203
|
+
console.log(` Input signal: 200 samples (bipolar with noise)`);
|
|
204
|
+
console.log(` After Rectify: All positive values`);
|
|
205
|
+
console.log(` After Variance: Variability measure`);
|
|
206
|
+
console.log(` Recent avg variance: ${avgVariance.toFixed(2)}`);
|
|
207
|
+
console.log(" (Can detect changes in signal amplitude variability)");
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
// Example 6: Threshold-based alerts
|
|
211
|
+
console.log("\n6. Variance-Based Alerting");
|
|
212
|
+
{
|
|
213
|
+
const pipeline = createDspPipeline().Variance({
|
|
214
|
+
mode: "moving",
|
|
215
|
+
windowSize: 50,
|
|
216
|
+
});
|
|
217
|
+
|
|
218
|
+
const VARIANCE_THRESHOLD = 100;
|
|
219
|
+
let alertCount = 0;
|
|
220
|
+
|
|
221
|
+
console.log(` Monitoring for variance > ${VARIANCE_THRESHOLD}:`);
|
|
222
|
+
|
|
223
|
+
// Simulate multiple data chunks
|
|
224
|
+
const chunks = [
|
|
225
|
+
new Float32Array(100).map((_, i) => 50 + Math.sin(i * 0.1) * 5), // Low variance
|
|
226
|
+
new Float32Array(100).map((_, i) => 50 + Math.sin(i * 0.1) * 50), // High variance
|
|
227
|
+
new Float32Array(100).map((_, i) => 50 + Math.sin(i * 0.1) * 10), // Moderate variance
|
|
228
|
+
];
|
|
229
|
+
|
|
230
|
+
for (let chunkIdx = 0; chunkIdx < chunks.length; chunkIdx++) {
|
|
231
|
+
const output = await pipeline.process(chunks[chunkIdx], {
|
|
232
|
+
sampleRate: 1000,
|
|
233
|
+
channels: 1,
|
|
234
|
+
});
|
|
235
|
+
|
|
236
|
+
// Check for threshold crossings
|
|
237
|
+
const exceedances = output.filter((v) => v > VARIANCE_THRESHOLD).length;
|
|
238
|
+
|
|
239
|
+
if (exceedances > 0) {
|
|
240
|
+
alertCount++;
|
|
241
|
+
console.log(
|
|
242
|
+
` Chunk ${
|
|
243
|
+
chunkIdx + 1
|
|
244
|
+
}: ALERT - ${exceedances} samples exceeded threshold`
|
|
245
|
+
);
|
|
246
|
+
} else {
|
|
247
|
+
console.log(` Chunk ${chunkIdx + 1}: OK - variance within limits`);
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
console.log(` Total alerts: ${alertCount}`);
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
console.log("\nStreaming Use Cases:");
|
|
255
|
+
console.log(" - Signal quality monitoring (batch variance per chunk)");
|
|
256
|
+
console.log(" - Real-time variability detection (moving window)");
|
|
257
|
+
console.log(" - Multi-channel muscle activity monitoring (EMG)");
|
|
258
|
+
console.log(" - Crash recovery with state persistence");
|
|
259
|
+
console.log(" - Feature extraction pipelines (combine with other filters)");
|
|
260
|
+
console.log(" - Threshold-based alerting for anomaly detection");
|