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,175 @@
|
|
|
1
|
+
# FIR Filter SIMD Optimization
|
|
2
|
+
|
|
3
|
+
## Overview
|
|
4
|
+
|
|
5
|
+
The FIR (Finite Impulse Response) filters in this library have been optimized with SIMD (Single Instruction Multiple Data) instructions for high-performance convolution operations.
|
|
6
|
+
|
|
7
|
+
## Implementation Details
|
|
8
|
+
|
|
9
|
+
### SIMD Dot Product
|
|
10
|
+
|
|
11
|
+
A vectorized dot product function was added to `SimdOps.h` that processes multiple coefficients simultaneously:
|
|
12
|
+
|
|
13
|
+
- **AVX2 (Intel/AMD)**: Processes 8 float values per cycle
|
|
14
|
+
- **SSE2 (Intel/AMD)**: Processes 4 float values per cycle
|
|
15
|
+
- **NEON (ARM)**: Processes 4 float values per cycle
|
|
16
|
+
- **Scalar Fallback**: Standard loop for platforms without SIMD support
|
|
17
|
+
|
|
18
|
+
### Performance Improvements
|
|
19
|
+
|
|
20
|
+
**Before**: Per-tap convolution loop
|
|
21
|
+
|
|
22
|
+
```cpp
|
|
23
|
+
for (size_t i = 0; i < coefficients.size(); ++i) {
|
|
24
|
+
output += samples[i] * coefficients[i];
|
|
25
|
+
}
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
**After**: Vectorized SIMD convolution
|
|
29
|
+
|
|
30
|
+
```cpp
|
|
31
|
+
output = simd::dot_product(samples.data(), coefficients.data(), coefficients.size());
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
**Expected Speedup**:
|
|
35
|
+
|
|
36
|
+
- **AVX2 platforms**: 4-8x faster convolution
|
|
37
|
+
- **SSE2 platforms**: 2-4x faster convolution
|
|
38
|
+
- **NEON platforms**: 2-4x faster convolution
|
|
39
|
+
|
|
40
|
+
### Architecture Integration
|
|
41
|
+
|
|
42
|
+
Created `FirConvolutionPolicy` in `Policies.h` to align FIR filters with the library's policy-based architecture:
|
|
43
|
+
|
|
44
|
+
```cpp
|
|
45
|
+
template <typename T>
|
|
46
|
+
struct FirConvolutionPolicy {
|
|
47
|
+
std::vector<T> m_coefficients;
|
|
48
|
+
T getResult(const std::vector<T> &buffer) const;
|
|
49
|
+
};
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
The policy defines the interface, while the SIMD implementation is applied in `FirFilter.cc` to avoid circular dependencies.
|
|
53
|
+
|
|
54
|
+
## Technical Details
|
|
55
|
+
|
|
56
|
+
### Horizontal Sum Implementation
|
|
57
|
+
|
|
58
|
+
The SIMD dot product uses efficient horizontal sum operations:
|
|
59
|
+
|
|
60
|
+
**AVX2**:
|
|
61
|
+
|
|
62
|
+
```cpp
|
|
63
|
+
// Extract high and low 128-bit lanes
|
|
64
|
+
__m128 hi = _mm256_extractf128_ps(acc, 1);
|
|
65
|
+
__m128 lo = _mm256_castps256_ps128(acc);
|
|
66
|
+
__m128 sum128 = _mm_add_ps(lo, hi);
|
|
67
|
+
// Horizontal add twice to get final sum
|
|
68
|
+
sum128 = _mm_hadd_ps(sum128, sum128);
|
|
69
|
+
sum128 = _mm_hadd_ps(sum128, sum128);
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
**SSE2**:
|
|
73
|
+
|
|
74
|
+
```cpp
|
|
75
|
+
// Shuffle-based horizontal reduction
|
|
76
|
+
__m128 shuf = _mm_shuffle_ps(acc, acc, _MM_SHUFFLE(2, 3, 0, 1));
|
|
77
|
+
acc = _mm_add_ps(acc, shuf);
|
|
78
|
+
shuf = _mm_shuffle_ps(acc, acc, _MM_SHUFFLE(1, 0, 3, 2));
|
|
79
|
+
acc = _mm_add_ps(acc, shuf);
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
**NEON**:
|
|
83
|
+
|
|
84
|
+
```cpp
|
|
85
|
+
// Pairwise add for horizontal sum
|
|
86
|
+
float32x2_t sum_pairs = vpadd_f32(vget_low_f32(acc), vget_high_f32(acc));
|
|
87
|
+
sum_pairs = vpadd_f32(sum_pairs, sum_pairs);
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
### Circular Buffer Alignment
|
|
91
|
+
|
|
92
|
+
Since FIR filters use circular buffers for state management, samples must be copied to an aligned buffer for optimal SIMD performance:
|
|
93
|
+
|
|
94
|
+
```cpp
|
|
95
|
+
std::vector<float> aligned_samples(m_coefficients.size());
|
|
96
|
+
for (size_t i = 0; i < m_coefficients.size(); ++i) {
|
|
97
|
+
size_t stateIdx = (m_stateIndex + m_state.size() - i) % m_state.size();
|
|
98
|
+
aligned_samples[i] = m_state[stateIdx];
|
|
99
|
+
}
|
|
100
|
+
output = simd::dot_product(aligned_samples.data(), m_coefficients.data(), m_coefficients.size());
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
### Template Support
|
|
104
|
+
|
|
105
|
+
SIMD optimization is conditionally applied based on data type:
|
|
106
|
+
|
|
107
|
+
```cpp
|
|
108
|
+
if constexpr (std::is_same_v<T, float>) {
|
|
109
|
+
// SIMD path for float precision
|
|
110
|
+
output = simd::dot_product(samples.data(), coefficients.data(), size);
|
|
111
|
+
} else {
|
|
112
|
+
// Scalar path for double precision
|
|
113
|
+
for (size_t i = 0; i < size; ++i) {
|
|
114
|
+
output += samples[i] * coefficients[i];
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
## Verification
|
|
120
|
+
|
|
121
|
+
All tests passing with SIMD optimizations:
|
|
122
|
+
|
|
123
|
+
- **Total Tests**: 395/395 ✅
|
|
124
|
+
- **Filter Tests**: All passing ✅
|
|
125
|
+
- **Correctness**: Outputs identical to pre-SIMD implementation ✅
|
|
126
|
+
- **Build**: 3013 functions compiled successfully ✅
|
|
127
|
+
|
|
128
|
+
## Compiler Flags
|
|
129
|
+
|
|
130
|
+
**MSVC**:
|
|
131
|
+
|
|
132
|
+
- `/O2` - Optimize for speed
|
|
133
|
+
- `/fp:fast` - Fast floating-point math
|
|
134
|
+
- `/arch:AVX2` - Enable AVX2 instructions
|
|
135
|
+
|
|
136
|
+
**GCC/Clang**:
|
|
137
|
+
|
|
138
|
+
- `-O3` - Maximum optimization
|
|
139
|
+
- `-ffast-math` - Fast floating-point math
|
|
140
|
+
- `-march=native` - Use native CPU instructions
|
|
141
|
+
|
|
142
|
+
## Usage
|
|
143
|
+
|
|
144
|
+
No changes required to the TypeScript API. The SIMD optimizations are transparent:
|
|
145
|
+
|
|
146
|
+
```typescript
|
|
147
|
+
const filter = dsp.createFirFilter({
|
|
148
|
+
type: "lowpass",
|
|
149
|
+
order: 50,
|
|
150
|
+
cutoffFrequency: 1000,
|
|
151
|
+
sampleRate: 8000,
|
|
152
|
+
});
|
|
153
|
+
|
|
154
|
+
// SIMD-optimized convolution happens automatically
|
|
155
|
+
const output = await filter.processSample(input);
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
## Future Enhancements
|
|
159
|
+
|
|
160
|
+
Potential improvements:
|
|
161
|
+
|
|
162
|
+
1. **IIR Filter SIMD**: Apply vectorization to IIR biquad sections
|
|
163
|
+
2. **Multi-threaded Convolution**: Parallel processing for large filter orders
|
|
164
|
+
3. **FFT-based Convolution**: Use frequency-domain convolution for very large filters
|
|
165
|
+
4. **Adaptive SIMD**: Runtime detection and selection of optimal SIMD path
|
|
166
|
+
|
|
167
|
+
## References
|
|
168
|
+
|
|
169
|
+
- **Intel Intrinsics Guide**: https://www.intel.com/content/www/us/en/docs/intrinsics-guide/
|
|
170
|
+
- **ARM NEON Intrinsics**: https://developer.arm.com/architectures/instruction-sets/intrinsics/
|
|
171
|
+
- **SIMD Everywhere**: Cross-platform SIMD abstraction library
|
|
172
|
+
|
|
173
|
+
## Summary
|
|
174
|
+
|
|
175
|
+
The FIR filter convolution has been successfully optimized with SIMD instructions, providing 4-8x speedup on modern CPUs while maintaining full backward compatibility and correctness. The implementation leverages AVX2, SSE2, and NEON instructions with automatic fallback to scalar code.
|
|
@@ -0,0 +1,350 @@
|
|
|
1
|
+
# Quick Reference: Logger API
|
|
2
|
+
|
|
3
|
+
## Installation
|
|
4
|
+
|
|
5
|
+
```typescript
|
|
6
|
+
import { Logger, createConsoleHandler, createLokiHandler } from "dspx";
|
|
7
|
+
```
|
|
8
|
+
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
## Creating a Logger
|
|
12
|
+
|
|
13
|
+
### Basic Logger
|
|
14
|
+
|
|
15
|
+
```typescript
|
|
16
|
+
const logger = new Logger([createConsoleHandler()]);
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
### Production Logger (Multiple Backends)
|
|
20
|
+
|
|
21
|
+
```typescript
|
|
22
|
+
const logger = new Logger([
|
|
23
|
+
createConsoleHandler(),
|
|
24
|
+
createLokiHandler({ endpoint: "...", apiKey: "..." }),
|
|
25
|
+
createPrometheusHandler({ endpoint: "..." }),
|
|
26
|
+
createPagerDutyHandler({ endpoint: "...", apiKey: "..." }),
|
|
27
|
+
createCloudWatchHandler({ endpoint: "...", apiKey: "..." }),
|
|
28
|
+
createDatadogHandler({ endpoint: "...", apiKey: "..." }),
|
|
29
|
+
]);
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
### With Custom Fallback Handler
|
|
33
|
+
|
|
34
|
+
```typescript
|
|
35
|
+
const customFallback = (log) => {
|
|
36
|
+
fs.appendFileSync("/var/log/dsp-errors.log", JSON.stringify(log));
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
const logger = new Logger([...handlers], customFallback);
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
---
|
|
43
|
+
|
|
44
|
+
## Logging Methods
|
|
45
|
+
|
|
46
|
+
### Basic Logging
|
|
47
|
+
|
|
48
|
+
```typescript
|
|
49
|
+
await logger.debug("Debug message");
|
|
50
|
+
await logger.info("Info message");
|
|
51
|
+
await logger.warn("Warning message");
|
|
52
|
+
await logger.error("Error message");
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
### With Topic
|
|
56
|
+
|
|
57
|
+
```typescript
|
|
58
|
+
await logger.info("Connection established", "redis.connection");
|
|
59
|
+
await logger.error("Processing failed", "dsp.filter.error");
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
### With Context
|
|
63
|
+
|
|
64
|
+
```typescript
|
|
65
|
+
await logger.info("Processing complete", "dsp.result", {
|
|
66
|
+
channels: 8,
|
|
67
|
+
samples: 10000,
|
|
68
|
+
duration_ms: 142,
|
|
69
|
+
filters: ["MovingAverage", "RMS"],
|
|
70
|
+
});
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
---
|
|
74
|
+
|
|
75
|
+
## Child Loggers
|
|
76
|
+
|
|
77
|
+
### Creating Child Loggers
|
|
78
|
+
|
|
79
|
+
```typescript
|
|
80
|
+
const appLogger = new Logger([...]);
|
|
81
|
+
|
|
82
|
+
// Child with prefix "pipeline"
|
|
83
|
+
const pipelineLogger = appLogger.child("pipeline");
|
|
84
|
+
|
|
85
|
+
// Nested child with prefix "pipeline.filter"
|
|
86
|
+
const filterLogger = pipelineLogger.child("filter");
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
### Usage
|
|
90
|
+
|
|
91
|
+
```typescript
|
|
92
|
+
// Logs to topic: "pipeline.filter.init"
|
|
93
|
+
await filterLogger.info("MovingAverage initialized", "init", {
|
|
94
|
+
windowSize: 10,
|
|
95
|
+
});
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
---
|
|
99
|
+
|
|
100
|
+
## Backend Handlers
|
|
101
|
+
|
|
102
|
+
### Console Handler
|
|
103
|
+
|
|
104
|
+
```typescript
|
|
105
|
+
createConsoleHandler(config?)
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
- **Use**: Development, debugging
|
|
109
|
+
- **Output**: Colored console logs with timestamps
|
|
110
|
+
|
|
111
|
+
### Loki Handler
|
|
112
|
+
|
|
113
|
+
```typescript
|
|
114
|
+
createLokiHandler({
|
|
115
|
+
endpoint: "https://loki.example.com",
|
|
116
|
+
apiKey: "your-api-key", // Optional
|
|
117
|
+
batchSize: 100, // Default: 100
|
|
118
|
+
flushInterval: 5000, // Default: 5000ms
|
|
119
|
+
});
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
- **Use**: Centralized log aggregation
|
|
123
|
+
- **Features**: Batching, auto-flush, resilient requeue
|
|
124
|
+
|
|
125
|
+
### Prometheus Handler
|
|
126
|
+
|
|
127
|
+
```typescript
|
|
128
|
+
createPrometheusHandler({
|
|
129
|
+
endpoint: "https://prometheus-pushgateway.example.com",
|
|
130
|
+
});
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
- **Use**: Metrics export
|
|
134
|
+
- **Format**: Prometheus text format
|
|
135
|
+
|
|
136
|
+
### PagerDuty Handler
|
|
137
|
+
|
|
138
|
+
```typescript
|
|
139
|
+
createPagerDutyHandler({
|
|
140
|
+
endpoint: "https://events.pagerduty.com/v2/enqueue",
|
|
141
|
+
apiKey: "your-routing-key",
|
|
142
|
+
});
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
- **Use**: Critical alerts, incident management
|
|
146
|
+
- **Severity**: error → critical, warn → warning
|
|
147
|
+
|
|
148
|
+
### CloudWatch Handler
|
|
149
|
+
|
|
150
|
+
```typescript
|
|
151
|
+
createCloudWatchHandler({
|
|
152
|
+
endpoint: "https://logs.amazonaws.com",
|
|
153
|
+
apiKey: "your-aws-credentials",
|
|
154
|
+
});
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
- **Use**: AWS-native logging
|
|
158
|
+
- **Format**: CloudWatch Logs JSON
|
|
159
|
+
|
|
160
|
+
### Datadog Handler
|
|
161
|
+
|
|
162
|
+
```typescript
|
|
163
|
+
createDatadogHandler({
|
|
164
|
+
endpoint: "https://http-intake.logs.datadoghq.com", // Default
|
|
165
|
+
apiKey: "your-datadog-api-key",
|
|
166
|
+
});
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
- **Use**: Unified observability platform
|
|
170
|
+
- **Features**: Tags, custom fields
|
|
171
|
+
|
|
172
|
+
### Mock Handler (Testing)
|
|
173
|
+
|
|
174
|
+
```typescript
|
|
175
|
+
const mock = createMockHandler((log) => {
|
|
176
|
+
console.log("Log received:", log);
|
|
177
|
+
});
|
|
178
|
+
|
|
179
|
+
// Get all captured logs
|
|
180
|
+
const logs = mock.getLogs();
|
|
181
|
+
|
|
182
|
+
// Clear captured logs
|
|
183
|
+
mock.clear();
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
---
|
|
187
|
+
|
|
188
|
+
## Advanced Patterns
|
|
189
|
+
|
|
190
|
+
### Error Isolation
|
|
191
|
+
|
|
192
|
+
```typescript
|
|
193
|
+
// One failing handler doesn't stop others
|
|
194
|
+
const logger = new Logger([
|
|
195
|
+
workingHandler1,
|
|
196
|
+
failingHandler, // ❌ Will fail
|
|
197
|
+
workingHandler2, // ✅ Still works
|
|
198
|
+
]);
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
### Conditional Logging
|
|
202
|
+
|
|
203
|
+
```typescript
|
|
204
|
+
const handlers = [createConsoleHandler()];
|
|
205
|
+
|
|
206
|
+
if (process.env.NODE_ENV === "production") {
|
|
207
|
+
handlers.push(createLokiHandler({ ... }));
|
|
208
|
+
handlers.push(createPagerDutyHandler({ ... }));
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
const logger = new Logger(handlers);
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
### Custom Handler
|
|
215
|
+
|
|
216
|
+
```typescript
|
|
217
|
+
const customHandler = async (log: LogEntry): Promise<void> => {
|
|
218
|
+
// Your custom logic
|
|
219
|
+
await sendToCustomAPI(log);
|
|
220
|
+
};
|
|
221
|
+
|
|
222
|
+
const logger = new Logger([customHandler, createConsoleHandler()]);
|
|
223
|
+
```
|
|
224
|
+
|
|
225
|
+
---
|
|
226
|
+
|
|
227
|
+
## Configuration Reference
|
|
228
|
+
|
|
229
|
+
### BackendConfig
|
|
230
|
+
|
|
231
|
+
```typescript
|
|
232
|
+
interface BackendConfig {
|
|
233
|
+
endpoint?: string; // API endpoint URL
|
|
234
|
+
apiKey?: string; // Authentication key/token
|
|
235
|
+
headers?: Record<string, string>; // Additional HTTP headers
|
|
236
|
+
batchSize?: number; // Batch size for buffering (Loki only)
|
|
237
|
+
flushInterval?: number; // Flush interval in ms (Loki only)
|
|
238
|
+
}
|
|
239
|
+
```
|
|
240
|
+
|
|
241
|
+
### LogEntry
|
|
242
|
+
|
|
243
|
+
```typescript
|
|
244
|
+
interface LogEntry {
|
|
245
|
+
level: "debug" | "info" | "warn" | "error";
|
|
246
|
+
message: string;
|
|
247
|
+
topic?: string;
|
|
248
|
+
context?: any;
|
|
249
|
+
timestamp: number; // Unix timestamp (milliseconds)
|
|
250
|
+
}
|
|
251
|
+
```
|
|
252
|
+
|
|
253
|
+
---
|
|
254
|
+
|
|
255
|
+
## Best Practices
|
|
256
|
+
|
|
257
|
+
### 1. Use Child Loggers for Modules
|
|
258
|
+
|
|
259
|
+
```typescript
|
|
260
|
+
// app.ts
|
|
261
|
+
const appLogger = new Logger([...]);
|
|
262
|
+
|
|
263
|
+
// pipeline.ts
|
|
264
|
+
export const pipelineLogger = appLogger.child("pipeline");
|
|
265
|
+
|
|
266
|
+
// filter.ts
|
|
267
|
+
export const filterLogger = pipelineLogger.child("filter");
|
|
268
|
+
```
|
|
269
|
+
|
|
270
|
+
### 2. Structured Context Over String Interpolation
|
|
271
|
+
|
|
272
|
+
```typescript
|
|
273
|
+
// ❌ Bad
|
|
274
|
+
await logger.info(`Processing ${count} samples in ${duration}ms`);
|
|
275
|
+
|
|
276
|
+
// ✅ Good
|
|
277
|
+
await logger.info("Processing complete", "dsp", {
|
|
278
|
+
samples: count,
|
|
279
|
+
duration_ms: duration,
|
|
280
|
+
});
|
|
281
|
+
```
|
|
282
|
+
|
|
283
|
+
### 3. Topic Naming Convention
|
|
284
|
+
|
|
285
|
+
```typescript
|
|
286
|
+
// Use dot-separated hierarchical topics
|
|
287
|
+
await logger.info("...", "app.module.component.event");
|
|
288
|
+
|
|
289
|
+
// Examples:
|
|
290
|
+
("dsp.pipeline.init");
|
|
291
|
+
("dsp.filter.mavg.processed");
|
|
292
|
+
("redis.connection.established");
|
|
293
|
+
("redis.connection.error");
|
|
294
|
+
```
|
|
295
|
+
|
|
296
|
+
### 4. Error Context
|
|
297
|
+
|
|
298
|
+
```typescript
|
|
299
|
+
try {
|
|
300
|
+
await processData();
|
|
301
|
+
} catch (error) {
|
|
302
|
+
await logger.error("Processing failed", "dsp.error", {
|
|
303
|
+
error: {
|
|
304
|
+
name: error.name,
|
|
305
|
+
message: error.message,
|
|
306
|
+
stack: error.stack,
|
|
307
|
+
},
|
|
308
|
+
input: { samples: data.length },
|
|
309
|
+
});
|
|
310
|
+
}
|
|
311
|
+
```
|
|
312
|
+
|
|
313
|
+
---
|
|
314
|
+
|
|
315
|
+
## Performance Tips
|
|
316
|
+
|
|
317
|
+
1. **Use batching** for high-volume logging (Loki handler)
|
|
318
|
+
2. **Limit concurrent handlers** to 5-10 max
|
|
319
|
+
3. **Use child loggers** to avoid repeating topic prefixes
|
|
320
|
+
4. **Filter debug logs** in production
|
|
321
|
+
5. **Monitor handler errors** via fallback logs
|
|
322
|
+
|
|
323
|
+
---
|
|
324
|
+
|
|
325
|
+
## Troubleshooting
|
|
326
|
+
|
|
327
|
+
### Logs Not Appearing?
|
|
328
|
+
|
|
329
|
+
- Check endpoint URL is correct
|
|
330
|
+
- Verify API keys are valid
|
|
331
|
+
- Check network connectivity
|
|
332
|
+
- Look for handler errors in fallback logs
|
|
333
|
+
|
|
334
|
+
### High Latency?
|
|
335
|
+
|
|
336
|
+
- Reduce number of handlers
|
|
337
|
+
- Increase Loki batch size
|
|
338
|
+
- Check backend endpoint response times
|
|
339
|
+
|
|
340
|
+
### Memory Usage High?
|
|
341
|
+
|
|
342
|
+
- Reduce Loki batch size
|
|
343
|
+
- Increase flush interval
|
|
344
|
+
- Limit buffer sizes
|
|
345
|
+
|
|
346
|
+
---
|
|
347
|
+
|
|
348
|
+
## Examples
|
|
349
|
+
|
|
350
|
+
See `src/ts/examples/logger-example.ts` for complete working examples.
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
# Notch Filter Quick Reference
|
|
2
|
+
|
|
3
|
+
## TL;DR
|
|
4
|
+
|
|
5
|
+
```typescript
|
|
6
|
+
import { FirFilter } from "./filters.js";
|
|
7
|
+
|
|
8
|
+
// Create 60 Hz notch filter
|
|
9
|
+
const notch = FirFilter.createBandStop({
|
|
10
|
+
lowCutoffFrequency: 58,
|
|
11
|
+
highCutoffFrequency: 62,
|
|
12
|
+
sampleRate: 1000,
|
|
13
|
+
order: 51,
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
// Process signal
|
|
17
|
+
const filtered = await notch.process(signal);
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
## Common Mistake
|
|
21
|
+
|
|
22
|
+
❌ **WRONG** - "notch" is not a type:
|
|
23
|
+
|
|
24
|
+
```typescript
|
|
25
|
+
const dsp = createDspPipeline().filter({type: "notch", ...})
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
✅ **CORRECT** - "notch" is a mode of band-stop:
|
|
29
|
+
|
|
30
|
+
```typescript
|
|
31
|
+
const notch = FirFilter.createBandStop({...})
|
|
32
|
+
// or
|
|
33
|
+
const notch = IirFilter.createBandStop({...}) // when implemented
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
## Filter API Structure
|
|
37
|
+
|
|
38
|
+
### Types (Implementation)
|
|
39
|
+
|
|
40
|
+
- `fir` - FIR filter
|
|
41
|
+
- `iir` - IIR filter
|
|
42
|
+
- `butterworth` - Butterworth IIR
|
|
43
|
+
- `chebyshev` - Chebyshev IIR
|
|
44
|
+
- `biquad` - Biquad IIR
|
|
45
|
+
|
|
46
|
+
### Modes (Frequency Response)
|
|
47
|
+
|
|
48
|
+
- `lowpass` - Pass low frequencies
|
|
49
|
+
- `highpass` - Pass high frequencies
|
|
50
|
+
- `bandpass` - Pass band of frequencies
|
|
51
|
+
- `bandstop` - Reject band (= notch)
|
|
52
|
+
- `notch` - Reject band (= bandstop)
|
|
53
|
+
|
|
54
|
+
## Common Use Cases
|
|
55
|
+
|
|
56
|
+
### 60 Hz Power Line Noise (US)
|
|
57
|
+
|
|
58
|
+
```typescript
|
|
59
|
+
FirFilter.createBandStop({
|
|
60
|
+
lowCutoffFrequency: 58,
|
|
61
|
+
highCutoffFrequency: 62,
|
|
62
|
+
sampleRate: 1000,
|
|
63
|
+
order: 51,
|
|
64
|
+
});
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
### 50 Hz Power Line Noise (EU)
|
|
68
|
+
|
|
69
|
+
```typescript
|
|
70
|
+
FirFilter.createBandStop({
|
|
71
|
+
lowCutoffFrequency: 49,
|
|
72
|
+
highCutoffFrequency: 51,
|
|
73
|
+
sampleRate: 1000,
|
|
74
|
+
order: 51,
|
|
75
|
+
});
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
### Multiple Harmonics
|
|
79
|
+
|
|
80
|
+
```typescript
|
|
81
|
+
const notch60 = FirFilter.createBandStop({
|
|
82
|
+
lowCutoffFrequency: 58,
|
|
83
|
+
highCutoffFrequency: 62,
|
|
84
|
+
sampleRate: 1000,
|
|
85
|
+
order: 51,
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
const notch120 = FirFilter.createBandStop({
|
|
89
|
+
lowCutoffFrequency: 118,
|
|
90
|
+
highCutoffFrequency: 122,
|
|
91
|
+
sampleRate: 1000,
|
|
92
|
+
order: 51,
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
// Chain them
|
|
96
|
+
const step1 = await notch60.process(signal);
|
|
97
|
+
const step2 = await notch120.process(step1);
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
## Pipeline Status
|
|
101
|
+
|
|
102
|
+
⚠️ **Not Yet Implemented**: Filter stages in DSP pipeline require C++ support.
|
|
103
|
+
|
|
104
|
+
**Workaround** - Use standalone filters:
|
|
105
|
+
|
|
106
|
+
```typescript
|
|
107
|
+
const dsp = createDspPipeline()
|
|
108
|
+
.MovingAverage({ mode: "moving", windowSize: 10 })
|
|
109
|
+
.Rectify({ mode: "full" });
|
|
110
|
+
|
|
111
|
+
const notch = FirFilter.createBandStop({...});
|
|
112
|
+
|
|
113
|
+
const pipelineOutput = await dsp.process(samples);
|
|
114
|
+
const finalOutput = await notch.process(pipelineOutput);
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
## See Also
|
|
118
|
+
|
|
119
|
+
- Full examples: `src/ts/examples/notch-filter-examples.ts`
|
|
120
|
+
- Filter API: `docs/FILTER_API_GUIDE.md`
|
|
121
|
+
- Tests: `src/ts/__tests__/AdvancedDsp.test.ts`
|