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,272 @@
|
|
|
1
|
+
import { describe, test, beforeEach } from "node:test";
|
|
2
|
+
import assert from "node:assert/strict";
|
|
3
|
+
import { createDspPipeline, DspProcessor } from "../bindings.js";
|
|
4
|
+
|
|
5
|
+
const DEFAULT_OPTIONS = { channels: 1, sampleRate: 44100 };
|
|
6
|
+
|
|
7
|
+
function assertCloseTo(actual: number, expected: number, precision = 5) {
|
|
8
|
+
const tolerance = Math.pow(10, -precision);
|
|
9
|
+
assert.ok(
|
|
10
|
+
Math.abs(actual - expected) < tolerance,
|
|
11
|
+
`Expected ${actual} to be close to ${expected} (tolerance: ${tolerance})`
|
|
12
|
+
);
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
describe("Rectify Filter", () => {
|
|
16
|
+
let processor: DspProcessor;
|
|
17
|
+
|
|
18
|
+
beforeEach(() => {
|
|
19
|
+
processor = createDspPipeline();
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
describe("Full-Wave Rectification", () => {
|
|
23
|
+
test("should convert all values to absolute (full-wave rectification)", async () => {
|
|
24
|
+
processor.Rectify({ mode: "full" });
|
|
25
|
+
|
|
26
|
+
const input = new Float32Array([1, -2, 3, -4, 5, -6]);
|
|
27
|
+
const output = await processor.process(input, DEFAULT_OPTIONS);
|
|
28
|
+
|
|
29
|
+
assert.equal(output.length, 6);
|
|
30
|
+
assertCloseTo(output[0], 1);
|
|
31
|
+
assertCloseTo(output[1], 2); // |-2| = 2
|
|
32
|
+
assertCloseTo(output[2], 3);
|
|
33
|
+
assertCloseTo(output[3], 4); // |-4| = 4
|
|
34
|
+
assertCloseTo(output[4], 5);
|
|
35
|
+
assertCloseTo(output[5], 6); // |-6| = 6
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
test("should default to full-wave when no mode specified", async () => {
|
|
39
|
+
processor.Rectify(); // No params
|
|
40
|
+
|
|
41
|
+
const input = new Float32Array([-5, 10, -15]);
|
|
42
|
+
const output = await processor.process(input, DEFAULT_OPTIONS);
|
|
43
|
+
|
|
44
|
+
assertCloseTo(output[0], 5);
|
|
45
|
+
assertCloseTo(output[1], 10);
|
|
46
|
+
assertCloseTo(output[2], 15);
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
test("should handle already positive values", async () => {
|
|
50
|
+
processor.Rectify({ mode: "full" });
|
|
51
|
+
|
|
52
|
+
const input = new Float32Array([1, 2, 3, 4, 5]);
|
|
53
|
+
const output = await processor.process(input, DEFAULT_OPTIONS);
|
|
54
|
+
|
|
55
|
+
assert.deepEqual(Array.from(output), [1, 2, 3, 4, 5]);
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
test("should handle zero values", async () => {
|
|
59
|
+
processor.Rectify({ mode: "full" });
|
|
60
|
+
|
|
61
|
+
const input = new Float32Array([0, -0, 0]);
|
|
62
|
+
const output = await processor.process(input, DEFAULT_OPTIONS);
|
|
63
|
+
|
|
64
|
+
assert.deepEqual(Array.from(output), [0, 0, 0]);
|
|
65
|
+
});
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
describe("Half-Wave Rectification", () => {
|
|
69
|
+
test("should keep positive values and zero negative values", async () => {
|
|
70
|
+
processor.Rectify({ mode: "half" });
|
|
71
|
+
|
|
72
|
+
const input = new Float32Array([1, -2, 3, -4, 5, -6]);
|
|
73
|
+
const output = await processor.process(input, DEFAULT_OPTIONS);
|
|
74
|
+
|
|
75
|
+
assert.equal(output.length, 6);
|
|
76
|
+
assertCloseTo(output[0], 1);
|
|
77
|
+
assertCloseTo(output[1], 0); // -2 → 0
|
|
78
|
+
assertCloseTo(output[2], 3);
|
|
79
|
+
assertCloseTo(output[3], 0); // -4 → 0
|
|
80
|
+
assertCloseTo(output[4], 5);
|
|
81
|
+
assertCloseTo(output[5], 0); // -6 → 0
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
test("should not affect positive values", async () => {
|
|
85
|
+
processor.Rectify({ mode: "half" });
|
|
86
|
+
|
|
87
|
+
const input = new Float32Array([10, 20, 30]);
|
|
88
|
+
const output = await processor.process(input, DEFAULT_OPTIONS);
|
|
89
|
+
|
|
90
|
+
assert.deepEqual(Array.from(output), [10, 20, 30]);
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
test("should handle mixed positive/negative pattern", async () => {
|
|
94
|
+
processor.Rectify({ mode: "half" });
|
|
95
|
+
|
|
96
|
+
const input = new Float32Array([5, -5, 10, -10, 15, -15]);
|
|
97
|
+
const output = await processor.process(input, DEFAULT_OPTIONS);
|
|
98
|
+
|
|
99
|
+
assertCloseTo(output[0], 5);
|
|
100
|
+
assertCloseTo(output[1], 0);
|
|
101
|
+
assertCloseTo(output[2], 10);
|
|
102
|
+
assertCloseTo(output[3], 0);
|
|
103
|
+
assertCloseTo(output[4], 15);
|
|
104
|
+
assertCloseTo(output[5], 0);
|
|
105
|
+
});
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
describe("State Management", () => {
|
|
109
|
+
test("should serialize and deserialize full-wave mode correctly", async () => {
|
|
110
|
+
processor.Rectify({ mode: "full" });
|
|
111
|
+
|
|
112
|
+
await processor.process(new Float32Array([1, -2, 3]), DEFAULT_OPTIONS);
|
|
113
|
+
|
|
114
|
+
const stateJson = await processor.saveState();
|
|
115
|
+
const state = JSON.parse(stateJson);
|
|
116
|
+
|
|
117
|
+
assert.ok(state);
|
|
118
|
+
assert.equal(state.stages.length, 1);
|
|
119
|
+
assert.equal(state.stages[0].type, "rectify");
|
|
120
|
+
assert.equal(state.stages[0].state.mode, "full");
|
|
121
|
+
|
|
122
|
+
// Load into new processor
|
|
123
|
+
const processor2 = createDspPipeline();
|
|
124
|
+
processor2.Rectify({ mode: "full" });
|
|
125
|
+
await processor2.loadState(stateJson);
|
|
126
|
+
|
|
127
|
+
const output = await processor2.process(
|
|
128
|
+
new Float32Array([-5, 10]),
|
|
129
|
+
DEFAULT_OPTIONS
|
|
130
|
+
);
|
|
131
|
+
assertCloseTo(output[0], 5);
|
|
132
|
+
assertCloseTo(output[1], 10);
|
|
133
|
+
});
|
|
134
|
+
|
|
135
|
+
test("should serialize and deserialize half-wave mode correctly", async () => {
|
|
136
|
+
processor.Rectify({ mode: "half" });
|
|
137
|
+
|
|
138
|
+
await processor.process(new Float32Array([1, -2, 3]), DEFAULT_OPTIONS);
|
|
139
|
+
|
|
140
|
+
const stateJson = await processor.saveState();
|
|
141
|
+
const state = JSON.parse(stateJson);
|
|
142
|
+
|
|
143
|
+
assert.equal(state.stages[0].state.mode, "half");
|
|
144
|
+
|
|
145
|
+
// Load into new processor
|
|
146
|
+
const processor2 = createDspPipeline();
|
|
147
|
+
processor2.Rectify({ mode: "half" });
|
|
148
|
+
await processor2.loadState(stateJson);
|
|
149
|
+
|
|
150
|
+
const output = await processor2.process(
|
|
151
|
+
new Float32Array([-5, 10]),
|
|
152
|
+
DEFAULT_OPTIONS
|
|
153
|
+
);
|
|
154
|
+
assertCloseTo(output[0], 0);
|
|
155
|
+
assertCloseTo(output[1], 10);
|
|
156
|
+
});
|
|
157
|
+
|
|
158
|
+
test("should preserve mode across state save/load", async () => {
|
|
159
|
+
processor.Rectify({ mode: "half" });
|
|
160
|
+
|
|
161
|
+
const stateJson = await processor.saveState();
|
|
162
|
+
|
|
163
|
+
// Create new processor with different mode
|
|
164
|
+
const processor2 = createDspPipeline();
|
|
165
|
+
processor2.Rectify({ mode: "half" }); // Must match for deserialization
|
|
166
|
+
|
|
167
|
+
await processor2.loadState(stateJson);
|
|
168
|
+
|
|
169
|
+
// Verify mode is preserved
|
|
170
|
+
const output = await processor2.process(
|
|
171
|
+
new Float32Array([-10, 10]),
|
|
172
|
+
DEFAULT_OPTIONS
|
|
173
|
+
);
|
|
174
|
+
assertCloseTo(output[0], 0); // Half-wave behavior
|
|
175
|
+
assertCloseTo(output[1], 10);
|
|
176
|
+
});
|
|
177
|
+
|
|
178
|
+
test("should handle reset (no-op for stateless filter)", async () => {
|
|
179
|
+
processor.Rectify({ mode: "full" });
|
|
180
|
+
|
|
181
|
+
await processor.process(new Float32Array([1, -2]), DEFAULT_OPTIONS);
|
|
182
|
+
processor.clearState();
|
|
183
|
+
|
|
184
|
+
const output = await processor.process(
|
|
185
|
+
new Float32Array([-5]),
|
|
186
|
+
DEFAULT_OPTIONS
|
|
187
|
+
);
|
|
188
|
+
assertCloseTo(output[0], 5); // Still works after reset
|
|
189
|
+
});
|
|
190
|
+
});
|
|
191
|
+
|
|
192
|
+
describe("Edge Cases", () => {
|
|
193
|
+
test("should handle empty input array", async () => {
|
|
194
|
+
processor.Rectify({ mode: "full" });
|
|
195
|
+
|
|
196
|
+
const output = await processor.process(
|
|
197
|
+
new Float32Array([]),
|
|
198
|
+
DEFAULT_OPTIONS
|
|
199
|
+
);
|
|
200
|
+
assert.equal(output.length, 0);
|
|
201
|
+
});
|
|
202
|
+
|
|
203
|
+
test("should handle single sample", async () => {
|
|
204
|
+
processor.Rectify({ mode: "half" });
|
|
205
|
+
|
|
206
|
+
const output1 = await processor.process(
|
|
207
|
+
new Float32Array([-10]),
|
|
208
|
+
DEFAULT_OPTIONS
|
|
209
|
+
);
|
|
210
|
+
assertCloseTo(output1[0], 0);
|
|
211
|
+
|
|
212
|
+
const output2 = await processor.process(
|
|
213
|
+
new Float32Array([10]),
|
|
214
|
+
DEFAULT_OPTIONS
|
|
215
|
+
);
|
|
216
|
+
assertCloseTo(output2[0], 10);
|
|
217
|
+
});
|
|
218
|
+
|
|
219
|
+
test("should handle very small negative values (half-wave)", async () => {
|
|
220
|
+
processor.Rectify({ mode: "half" });
|
|
221
|
+
|
|
222
|
+
const input = new Float32Array([-0.0001, -0.00001, -0.000001]);
|
|
223
|
+
const output = await processor.process(input, DEFAULT_OPTIONS);
|
|
224
|
+
|
|
225
|
+
assert.deepEqual(Array.from(output), [0, 0, 0]);
|
|
226
|
+
});
|
|
227
|
+
|
|
228
|
+
test("should handle very large values", async () => {
|
|
229
|
+
processor.Rectify({ mode: "full" });
|
|
230
|
+
|
|
231
|
+
const input = new Float32Array([-1e6, 1e6, -1e9]);
|
|
232
|
+
const output = await processor.process(input, DEFAULT_OPTIONS);
|
|
233
|
+
|
|
234
|
+
assertCloseTo(output[0], 1e6);
|
|
235
|
+
assertCloseTo(output[1], 1e6);
|
|
236
|
+
assertCloseTo(output[2], 1e9);
|
|
237
|
+
});
|
|
238
|
+
});
|
|
239
|
+
|
|
240
|
+
describe("Multi-channel Processing", () => {
|
|
241
|
+
test("should rectify multiple channels independently", async () => {
|
|
242
|
+
processor.Rectify({ mode: "full" });
|
|
243
|
+
|
|
244
|
+
const input = new Float32Array([-1, -2, -3, -4, -5, -6]);
|
|
245
|
+
const output = await processor.process(input, DEFAULT_OPTIONS);
|
|
246
|
+
|
|
247
|
+
// All should be positive
|
|
248
|
+
assert.ok(Array.from(output).every((v) => v >= 0));
|
|
249
|
+
assertCloseTo(output[0], 1);
|
|
250
|
+
assertCloseTo(output[1], 2);
|
|
251
|
+
assertCloseTo(output[2], 3);
|
|
252
|
+
});
|
|
253
|
+
|
|
254
|
+
test("should handle multiple process calls with state continuity", async () => {
|
|
255
|
+
processor.Rectify({ mode: "half" });
|
|
256
|
+
|
|
257
|
+
const output1 = await processor.process(
|
|
258
|
+
new Float32Array([5, -5]),
|
|
259
|
+
DEFAULT_OPTIONS
|
|
260
|
+
);
|
|
261
|
+
assertCloseTo(output1[0], 5);
|
|
262
|
+
assertCloseTo(output1[1], 0);
|
|
263
|
+
|
|
264
|
+
const output2 = await processor.process(
|
|
265
|
+
new Float32Array([10, -10]),
|
|
266
|
+
DEFAULT_OPTIONS
|
|
267
|
+
);
|
|
268
|
+
assertCloseTo(output2[0], 10);
|
|
269
|
+
assertCloseTo(output2[1], 0);
|
|
270
|
+
});
|
|
271
|
+
});
|
|
272
|
+
});
|