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,397 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Advanced DSP Operations Examples
|
|
3
|
+
*
|
|
4
|
+
* Demonstrates the new advanced DSP features:
|
|
5
|
+
* - Hjorth Parameters (Activity, Mobility, Complexity)
|
|
6
|
+
* - Spectral Features (Centroid, Rolloff, Flux)
|
|
7
|
+
* - Entropy Measures (Shannon, Sample Entropy, Approximate Entropy)
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import {
|
|
11
|
+
calculateHjorthParameters,
|
|
12
|
+
calculateSpectralFeatures,
|
|
13
|
+
calculateShannonEntropy,
|
|
14
|
+
calculateSampleEntropy,
|
|
15
|
+
calculateApproximateEntropy,
|
|
16
|
+
HjorthTracker,
|
|
17
|
+
SpectralFeaturesTracker,
|
|
18
|
+
EntropyTracker,
|
|
19
|
+
} from "../advanced-dsp.js";
|
|
20
|
+
import { FftProcessor } from "../fft.js";
|
|
21
|
+
|
|
22
|
+
console.log("=== Advanced DSP Operations Examples ===\n");
|
|
23
|
+
|
|
24
|
+
const sampleRate = 1000; // 1 kHz
|
|
25
|
+
|
|
26
|
+
// ============================================================
|
|
27
|
+
// Example 1: Hjorth Parameters - Signal Complexity Analysis
|
|
28
|
+
// ============================================================
|
|
29
|
+
|
|
30
|
+
console.log("--- Example 1: Hjorth Parameters ---");
|
|
31
|
+
|
|
32
|
+
// Create test signals with different complexity
|
|
33
|
+
const simpleSignal = new Float32Array(200);
|
|
34
|
+
const complexSignal = new Float32Array(200);
|
|
35
|
+
const noisySignal = new Float32Array(200);
|
|
36
|
+
|
|
37
|
+
for (let i = 0; i < 200; i++) {
|
|
38
|
+
// Simple: smooth sine wave
|
|
39
|
+
simpleSignal[i] = Math.sin((2 * Math.PI * 5 * i) / sampleRate);
|
|
40
|
+
|
|
41
|
+
// Complex: mix of multiple frequencies
|
|
42
|
+
complexSignal[i] =
|
|
43
|
+
Math.sin((2 * Math.PI * 5 * i) / sampleRate) +
|
|
44
|
+
0.5 * Math.sin((2 * Math.PI * 15 * i) / sampleRate) +
|
|
45
|
+
0.3 * Math.sin((2 * Math.PI * 30 * i) / sampleRate);
|
|
46
|
+
|
|
47
|
+
// Noisy: sine wave + random noise
|
|
48
|
+
noisySignal[i] =
|
|
49
|
+
Math.sin((2 * Math.PI * 5 * i) / sampleRate) + (Math.random() - 0.5) * 0.3;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
const hjorthSimple = calculateHjorthParameters(simpleSignal);
|
|
53
|
+
const hjorthComplex = calculateHjorthParameters(complexSignal);
|
|
54
|
+
const hjorthNoisy = calculateHjorthParameters(noisySignal);
|
|
55
|
+
|
|
56
|
+
console.log("Simple signal (smooth sine):");
|
|
57
|
+
console.log(` Activity: ${hjorthSimple.activity.toFixed(4)}`);
|
|
58
|
+
console.log(` Mobility: ${hjorthSimple.mobility.toFixed(4)}`);
|
|
59
|
+
console.log(` Complexity: ${hjorthSimple.complexity.toFixed(4)}`);
|
|
60
|
+
|
|
61
|
+
console.log("\nComplex signal (multi-frequency):");
|
|
62
|
+
console.log(` Activity: ${hjorthComplex.activity.toFixed(4)}`);
|
|
63
|
+
console.log(` Mobility: ${hjorthComplex.mobility.toFixed(4)}`);
|
|
64
|
+
console.log(` Complexity: ${hjorthComplex.complexity.toFixed(4)}`);
|
|
65
|
+
|
|
66
|
+
console.log("\nNoisy signal:");
|
|
67
|
+
console.log(` Activity: ${hjorthNoisy.activity.toFixed(4)}`);
|
|
68
|
+
console.log(` Mobility: ${hjorthNoisy.mobility.toFixed(4)}`);
|
|
69
|
+
console.log(` Complexity: ${hjorthNoisy.complexity.toFixed(4)}`);
|
|
70
|
+
|
|
71
|
+
console.log(
|
|
72
|
+
"\n✅ Higher complexity indicates more irregular/unpredictable signal\n"
|
|
73
|
+
);
|
|
74
|
+
|
|
75
|
+
// ============================================================
|
|
76
|
+
// Example 2: Hjorth Tracker - Real-Time Monitoring
|
|
77
|
+
// ============================================================
|
|
78
|
+
|
|
79
|
+
console.log("--- Example 2: Hjorth Tracker (Sliding Window) ---");
|
|
80
|
+
|
|
81
|
+
const tracker = new HjorthTracker(100);
|
|
82
|
+
|
|
83
|
+
console.log("Processing samples one at a time...");
|
|
84
|
+
for (let i = 0; i < 150; i++) {
|
|
85
|
+
const sample =
|
|
86
|
+
Math.sin((2 * Math.PI * 5 * i) / sampleRate) + (Math.random() - 0.5) * 0.1;
|
|
87
|
+
const hjorth = tracker.update(sample);
|
|
88
|
+
|
|
89
|
+
if (hjorth && i % 50 === 0) {
|
|
90
|
+
console.log(` Sample ${i}:`);
|
|
91
|
+
console.log(` Activity: ${hjorth.activity.toFixed(4)}`);
|
|
92
|
+
console.log(` Mobility: ${hjorth.mobility.toFixed(4)}`);
|
|
93
|
+
console.log(` Complexity: ${hjorth.complexity.toFixed(4)}`);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
console.log("✅ Real-time Hjorth tracking for continuous monitoring\n");
|
|
98
|
+
|
|
99
|
+
// ============================================================
|
|
100
|
+
// Example 3: Spectral Features - Frequency Content Analysis
|
|
101
|
+
// ============================================================
|
|
102
|
+
|
|
103
|
+
console.log("--- Example 3: Spectral Features ---");
|
|
104
|
+
|
|
105
|
+
// Create test signal with specific frequency content
|
|
106
|
+
const fftSize = 2048;
|
|
107
|
+
const testSignal = new Float32Array(fftSize);
|
|
108
|
+
|
|
109
|
+
// Low-frequency dominated signal
|
|
110
|
+
for (let i = 0; i < fftSize; i++) {
|
|
111
|
+
testSignal[i] =
|
|
112
|
+
2.0 * Math.sin((2 * Math.PI * 100 * i) / sampleRate) + // Strong 100 Hz
|
|
113
|
+
0.5 * Math.sin((2 * Math.PI * 500 * i) / sampleRate); // Weak 500 Hz
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
// Perform FFT
|
|
117
|
+
const fft = new FftProcessor(fftSize);
|
|
118
|
+
const spectrum = fft.rfft(testSignal);
|
|
119
|
+
const magnitude = fft.getMagnitude(spectrum);
|
|
120
|
+
|
|
121
|
+
// Calculate spectral features
|
|
122
|
+
const features = calculateSpectralFeatures(magnitude, sampleRate);
|
|
123
|
+
|
|
124
|
+
console.log("Signal with 100 Hz (strong) + 500 Hz (weak):");
|
|
125
|
+
console.log(` Spectral Centroid: ${features.centroid.toFixed(2)} Hz`);
|
|
126
|
+
console.log(` Spectral Rolloff (85%): ${features.rolloff.toFixed(2)} Hz`);
|
|
127
|
+
console.log(` Spectral Flux: ${features.flux.toFixed(4)}`);
|
|
128
|
+
|
|
129
|
+
console.log("\n✅ Centroid shows center of frequency mass");
|
|
130
|
+
console.log("✅ Rolloff shows where most energy is contained\n");
|
|
131
|
+
|
|
132
|
+
// ============================================================
|
|
133
|
+
// Example 4: Spectral Features Tracker - Frame-by-Frame
|
|
134
|
+
// ============================================================
|
|
135
|
+
|
|
136
|
+
console.log("--- Example 4: Spectral Features Tracker ---");
|
|
137
|
+
|
|
138
|
+
const spectralTracker = new SpectralFeaturesTracker();
|
|
139
|
+
|
|
140
|
+
// Simulate changing frequency content over frames
|
|
141
|
+
console.log("Processing frames with changing frequency content...");
|
|
142
|
+
|
|
143
|
+
for (let frame = 0; frame < 3; frame++) {
|
|
144
|
+
const frameSignal = new Float32Array(fftSize);
|
|
145
|
+
const baseFreq = 200 + frame * 100; // Frequency increases each frame
|
|
146
|
+
|
|
147
|
+
for (let i = 0; i < fftSize; i++) {
|
|
148
|
+
frameSignal[i] = Math.sin((2 * Math.PI * baseFreq * i) / sampleRate);
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
const spectrum = fft.rfft(frameSignal);
|
|
152
|
+
const magnitude = fft.getMagnitude(spectrum);
|
|
153
|
+
const frameFeatures = spectralTracker.calculate(magnitude, sampleRate);
|
|
154
|
+
|
|
155
|
+
console.log(` Frame ${frame + 1} (${baseFreq} Hz):`);
|
|
156
|
+
console.log(` Centroid: ${frameFeatures.centroid.toFixed(2)} Hz`);
|
|
157
|
+
console.log(` Flux: ${frameFeatures.flux.toFixed(4)}`);
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
console.log("✅ Flux tracks changes in spectrum between consecutive frames\n");
|
|
161
|
+
|
|
162
|
+
// ============================================================
|
|
163
|
+
// Example 5: Shannon Entropy - Signal Randomness
|
|
164
|
+
// ============================================================
|
|
165
|
+
|
|
166
|
+
console.log("--- Example 5: Shannon Entropy ---");
|
|
167
|
+
|
|
168
|
+
// Deterministic signal (low entropy)
|
|
169
|
+
const deterministicSignal = new Float32Array(1000);
|
|
170
|
+
for (let i = 0; i < 1000; i++) {
|
|
171
|
+
deterministicSignal[i] = Math.sin((2 * Math.PI * 10 * i) / sampleRate);
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
// Random signal (high entropy)
|
|
175
|
+
const randomSignal = new Float32Array(1000);
|
|
176
|
+
for (let i = 0; i < 1000; i++) {
|
|
177
|
+
randomSignal[i] = Math.random() * 2 - 1;
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
// Mixed signal (medium entropy)
|
|
181
|
+
const mixedSignal = new Float32Array(1000);
|
|
182
|
+
for (let i = 0; i < 1000; i++) {
|
|
183
|
+
mixedSignal[i] =
|
|
184
|
+
0.7 * Math.sin((2 * Math.PI * 10 * i) / sampleRate) +
|
|
185
|
+
0.3 * (Math.random() * 2 - 1);
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
const entropyDeterministic = calculateShannonEntropy(deterministicSignal, 256);
|
|
189
|
+
const entropyRandom = calculateShannonEntropy(randomSignal, 256);
|
|
190
|
+
const entropyMixed = calculateShannonEntropy(mixedSignal, 256);
|
|
191
|
+
|
|
192
|
+
console.log("Deterministic signal (pure sine):");
|
|
193
|
+
console.log(` Shannon Entropy: ${entropyDeterministic.toFixed(4)} bits`);
|
|
194
|
+
|
|
195
|
+
console.log("\nRandom signal (uniform noise):");
|
|
196
|
+
console.log(` Shannon Entropy: ${entropyRandom.toFixed(4)} bits`);
|
|
197
|
+
|
|
198
|
+
console.log("\nMixed signal (sine + noise):");
|
|
199
|
+
console.log(` Shannon Entropy: ${entropyMixed.toFixed(4)} bits`);
|
|
200
|
+
|
|
201
|
+
console.log("\n✅ Higher entropy = more unpredictable/random signal\n");
|
|
202
|
+
|
|
203
|
+
// ============================================================
|
|
204
|
+
// Example 6: Entropy Tracker - Real-Time Randomness Monitoring
|
|
205
|
+
// ============================================================
|
|
206
|
+
|
|
207
|
+
console.log("--- Example 6: Entropy Tracker ---");
|
|
208
|
+
|
|
209
|
+
const entropyTracker = new EntropyTracker(200, 128);
|
|
210
|
+
|
|
211
|
+
console.log(
|
|
212
|
+
"Monitoring entropy as signal transitions from periodic to random..."
|
|
213
|
+
);
|
|
214
|
+
|
|
215
|
+
for (let i = 0; i < 300; i++) {
|
|
216
|
+
// Transition from sine wave to noise
|
|
217
|
+
const noiseLevel = Math.min(i / 300, 1.0);
|
|
218
|
+
const sample =
|
|
219
|
+
(1 - noiseLevel) * Math.sin((2 * Math.PI * 10 * i) / sampleRate) +
|
|
220
|
+
noiseLevel * (Math.random() * 2 - 1);
|
|
221
|
+
|
|
222
|
+
const entropy = entropyTracker.update(sample);
|
|
223
|
+
|
|
224
|
+
if (entropy !== null && i % 100 === 0) {
|
|
225
|
+
console.log(` Sample ${i}: Entropy = ${entropy.toFixed(4)} bits`);
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
console.log("✅ Entropy increases as signal becomes more random\n");
|
|
230
|
+
|
|
231
|
+
// ============================================================
|
|
232
|
+
// Example 7: Sample Entropy (SampEn) - Pattern Regularity
|
|
233
|
+
// ============================================================
|
|
234
|
+
|
|
235
|
+
console.log("--- Example 7: Sample Entropy ---");
|
|
236
|
+
|
|
237
|
+
// Regular periodic signal
|
|
238
|
+
const regularSignal = new Float32Array(500);
|
|
239
|
+
for (let i = 0; i < 500; i++) {
|
|
240
|
+
regularSignal[i] = Math.sin((2 * Math.PI * 5 * i) / sampleRate);
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
// Chaotic signal (more irregular)
|
|
244
|
+
const chaoticSignal = new Float32Array(500);
|
|
245
|
+
for (let i = 0; i < 500; i++) {
|
|
246
|
+
chaoticSignal[i] =
|
|
247
|
+
Math.sin((2 * Math.PI * 5 * i) / sampleRate) +
|
|
248
|
+
0.5 * Math.sin((2 * Math.PI * 13.7 * i) / sampleRate) +
|
|
249
|
+
0.3 * Math.sin((2 * Math.PI * 23.1 * i) / sampleRate);
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
try {
|
|
253
|
+
const sampEnRegular = calculateSampleEntropy(regularSignal, 2);
|
|
254
|
+
const sampEnChaotic = calculateSampleEntropy(chaoticSignal, 2);
|
|
255
|
+
|
|
256
|
+
console.log("Regular periodic signal:");
|
|
257
|
+
console.log(` Sample Entropy: ${sampEnRegular.toFixed(4)}`);
|
|
258
|
+
|
|
259
|
+
console.log("\nChaotic signal:");
|
|
260
|
+
console.log(` Sample Entropy: ${sampEnChaotic.toFixed(4)}`);
|
|
261
|
+
|
|
262
|
+
console.log(
|
|
263
|
+
"\n✅ Lower SampEn = more regular patterns, Higher SampEn = more chaotic\n"
|
|
264
|
+
);
|
|
265
|
+
} catch (error) {
|
|
266
|
+
console.log("Note: SampEn calculation can be computationally intensive\n");
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
// ============================================================
|
|
270
|
+
// Example 8: Approximate Entropy (ApEn) - Faster Alternative
|
|
271
|
+
// ============================================================
|
|
272
|
+
|
|
273
|
+
console.log("--- Example 8: Approximate Entropy ---");
|
|
274
|
+
|
|
275
|
+
const apEnRegular = calculateApproximateEntropy(regularSignal, 2);
|
|
276
|
+
const apEnChaotic = calculateApproximateEntropy(chaoticSignal, 2);
|
|
277
|
+
|
|
278
|
+
console.log("Regular periodic signal:");
|
|
279
|
+
console.log(` Approximate Entropy: ${apEnRegular.toFixed(4)}`);
|
|
280
|
+
|
|
281
|
+
console.log("\nChaotic signal:");
|
|
282
|
+
console.log(` Approximate Entropy: ${apEnChaotic.toFixed(4)}`);
|
|
283
|
+
|
|
284
|
+
console.log("\n✅ ApEn is faster than SampEn but may have more bias\n");
|
|
285
|
+
|
|
286
|
+
// ============================================================
|
|
287
|
+
// Example 9: Real-World Application - EMG Signal Analysis
|
|
288
|
+
// ============================================================
|
|
289
|
+
|
|
290
|
+
console.log("--- Example 9: EMG Signal Analysis Use Case ---");
|
|
291
|
+
|
|
292
|
+
// Simulate EMG signal (muscle activity)
|
|
293
|
+
const emgSignal = new Float32Array(2000);
|
|
294
|
+
for (let i = 0; i < 2000; i++) {
|
|
295
|
+
// Mix of frequencies typical in EMG (20-450 Hz)
|
|
296
|
+
emgSignal[i] =
|
|
297
|
+
0.3 * Math.sin((2 * Math.PI * 50 * i) / sampleRate) +
|
|
298
|
+
0.5 * Math.sin((2 * Math.PI * 120 * i) / sampleRate) +
|
|
299
|
+
0.4 * Math.sin((2 * Math.PI * 250 * i) / sampleRate) +
|
|
300
|
+
0.2 * (Math.random() * 2 - 1);
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
const emgHjorth = calculateHjorthParameters(emgSignal);
|
|
304
|
+
const emgEntropy = calculateShannonEntropy(emgSignal, 256);
|
|
305
|
+
|
|
306
|
+
console.log("EMG Signal Analysis:");
|
|
307
|
+
console.log(` Hjorth Activity: ${emgHjorth.activity.toFixed(4)}`);
|
|
308
|
+
console.log(` Hjorth Mobility: ${emgHjorth.mobility.toFixed(4)}`);
|
|
309
|
+
console.log(` Hjorth Complexity: ${emgHjorth.complexity.toFixed(4)}`);
|
|
310
|
+
console.log(` Shannon Entropy: ${emgEntropy.toFixed(4)} bits`);
|
|
311
|
+
|
|
312
|
+
console.log("\n✅ Combined features useful for:");
|
|
313
|
+
console.log(" - Muscle fatigue detection (Hjorth Mobility trends)");
|
|
314
|
+
console.log(" - Signal quality assessment (Entropy)");
|
|
315
|
+
console.log(" - Activity level classification (Hjorth Activity)\n");
|
|
316
|
+
|
|
317
|
+
// ============================================================
|
|
318
|
+
// Example 10: EEG/Biosignal Monitoring Pipeline
|
|
319
|
+
// ============================================================
|
|
320
|
+
|
|
321
|
+
console.log("--- Example 10: Complete Monitoring Pipeline ---");
|
|
322
|
+
|
|
323
|
+
console.log("Real-time biosignal monitoring:");
|
|
324
|
+
|
|
325
|
+
const monitoringTracker = new HjorthTracker(250);
|
|
326
|
+
const monitoringEntropy = new EntropyTracker(250, 128);
|
|
327
|
+
|
|
328
|
+
// Simulate streaming data
|
|
329
|
+
console.log("Processing 1000 samples in sliding windows...");
|
|
330
|
+
|
|
331
|
+
let complexityWarnings = 0;
|
|
332
|
+
let entropyWarnings = 0;
|
|
333
|
+
|
|
334
|
+
for (let i = 0; i < 1000; i++) {
|
|
335
|
+
// Simulate changing signal conditions
|
|
336
|
+
const signal =
|
|
337
|
+
Math.sin((2 * Math.PI * 10 * i) / sampleRate) +
|
|
338
|
+
(Math.random() - 0.5) * (i > 500 ? 0.8 : 0.2); // Noise increases halfway
|
|
339
|
+
|
|
340
|
+
const hjorth = monitoringTracker.update(signal);
|
|
341
|
+
const entropy = monitoringEntropy.update(signal);
|
|
342
|
+
|
|
343
|
+
if (hjorth && entropy !== null && i % 250 === 0) {
|
|
344
|
+
console.log(` Checkpoint at sample ${i}:`);
|
|
345
|
+
console.log(` Complexity: ${hjorth.complexity.toFixed(4)}`);
|
|
346
|
+
console.log(` Entropy: ${entropy.toFixed(4)} bits`);
|
|
347
|
+
|
|
348
|
+
// Detect abnormal conditions
|
|
349
|
+
if (hjorth.complexity > 2.0) {
|
|
350
|
+
console.log(` ⚠️ High complexity detected`);
|
|
351
|
+
complexityWarnings++;
|
|
352
|
+
}
|
|
353
|
+
if (entropy > 6.0) {
|
|
354
|
+
console.log(` ⚠️ High entropy detected`);
|
|
355
|
+
entropyWarnings++;
|
|
356
|
+
}
|
|
357
|
+
}
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
console.log(`\n✅ Detected ${complexityWarnings} complexity warnings`);
|
|
361
|
+
console.log(`✅ Detected ${entropyWarnings} entropy warnings`);
|
|
362
|
+
console.log("✅ Real-time monitoring enables early anomaly detection\n");
|
|
363
|
+
|
|
364
|
+
// ============================================================
|
|
365
|
+
// Summary
|
|
366
|
+
// ============================================================
|
|
367
|
+
|
|
368
|
+
console.log("=== Summary ===");
|
|
369
|
+
|
|
370
|
+
console.log("\n✅ Hjorth Parameters:");
|
|
371
|
+
console.log(" - Activity: Signal variance (power)");
|
|
372
|
+
console.log(" - Mobility: Rate of change");
|
|
373
|
+
console.log(" - Complexity: Change of change (irregularity)");
|
|
374
|
+
console.log(" - Use: EMG/EEG analysis, signal quality");
|
|
375
|
+
|
|
376
|
+
console.log("\n✅ Spectral Features:");
|
|
377
|
+
console.log(" - Centroid: Frequency center of mass");
|
|
378
|
+
console.log(" - Rolloff: Energy concentration point");
|
|
379
|
+
console.log(" - Flux: Frame-to-frame spectral change");
|
|
380
|
+
console.log(" - Use: Audio analysis, speech processing");
|
|
381
|
+
|
|
382
|
+
console.log("\n✅ Entropy Measures:");
|
|
383
|
+
console.log(" - Shannon: Amplitude distribution randomness");
|
|
384
|
+
console.log(" - Sample Entropy: Pattern regularity");
|
|
385
|
+
console.log(" - Approximate Entropy: Faster alternative to SampEn");
|
|
386
|
+
console.log(" - Use: Complexity analysis, anomaly detection");
|
|
387
|
+
|
|
388
|
+
console.log("\n✅ Stateful Trackers:");
|
|
389
|
+
console.log(" - HjorthTracker: Sliding window Hjorth parameters");
|
|
390
|
+
console.log(" - SpectralFeaturesTracker: Frame-by-frame features");
|
|
391
|
+
console.log(" - EntropyTracker: Sliding window entropy");
|
|
392
|
+
console.log(" - Use: Real-time monitoring, streaming analysis");
|
|
393
|
+
|
|
394
|
+
console.log("\n📚 All implemented in pure TypeScript for flexibility!");
|
|
395
|
+
console.log(
|
|
396
|
+
"🚀 Use with existing FFT and filter operations for complete DSP pipelines!"
|
|
397
|
+
);
|