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.
Files changed (172) hide show
  1. package/.github/workflows/ci.yml +185 -0
  2. package/.vscode/c_cpp_properties.json +17 -0
  3. package/.vscode/settings.json +68 -0
  4. package/.vscode/tasks.json +28 -0
  5. package/DISCLAIMER.md +32 -0
  6. package/LICENSE +21 -0
  7. package/README.md +1803 -0
  8. package/ROADMAP.md +192 -0
  9. package/TECHNICAL_DEBT.md +165 -0
  10. package/binding.gyp +65 -0
  11. package/docs/ADVANCED_LOGGER_FEATURES.md +598 -0
  12. package/docs/AUTHENTICATION_SECURITY.md +396 -0
  13. package/docs/BACKEND_IMPROVEMENTS.md +399 -0
  14. package/docs/CHEBYSHEV_BIQUAD_EQ_IMPLEMENTATION.md +405 -0
  15. package/docs/FFT_IMPLEMENTATION.md +490 -0
  16. package/docs/FFT_IMPROVEMENTS_SUMMARY.md +387 -0
  17. package/docs/FFT_USER_GUIDE.md +494 -0
  18. package/docs/FILTERS_IMPLEMENTATION.md +260 -0
  19. package/docs/FILTER_API_GUIDE.md +418 -0
  20. package/docs/FIR_SIMD_OPTIMIZATION.md +175 -0
  21. package/docs/LOGGER_API_REFERENCE.md +350 -0
  22. package/docs/NOTCH_FILTER_QUICK_REF.md +121 -0
  23. package/docs/PHASE2_TESTS_AND_NOTCH_FILTER.md +341 -0
  24. package/docs/PHASES_5_7_SUMMARY.md +403 -0
  25. package/docs/PIPELINE_FILTER_INTEGRATION.md +446 -0
  26. package/docs/SIMD_OPTIMIZATIONS.md +211 -0
  27. package/docs/TEST_MIGRATION_SUMMARY.md +173 -0
  28. package/docs/TIMESERIES_IMPLEMENTATION_SUMMARY.md +322 -0
  29. package/docs/TIMESERIES_QUICK_REF.md +85 -0
  30. package/docs/advanced.md +559 -0
  31. package/docs/time-series-guide.md +617 -0
  32. package/docs/time-series-migration.md +376 -0
  33. package/jest.config.js +37 -0
  34. package/package.json +42 -0
  35. package/prebuilds/linux-x64/dsp-ts-redis.node +0 -0
  36. package/prebuilds/win32-x64/dsp-ts-redis.node +0 -0
  37. package/scripts/test.js +24 -0
  38. package/src/build/dsp-ts-redis.node +0 -0
  39. package/src/native/DspPipeline.cc +675 -0
  40. package/src/native/DspPipeline.h +44 -0
  41. package/src/native/FftBindings.cc +817 -0
  42. package/src/native/FilterBindings.cc +1001 -0
  43. package/src/native/IDspStage.h +53 -0
  44. package/src/native/adapters/InterpolatorStage.h +201 -0
  45. package/src/native/adapters/MeanAbsoluteValueStage.h +289 -0
  46. package/src/native/adapters/MovingAverageStage.h +306 -0
  47. package/src/native/adapters/RectifyStage.h +88 -0
  48. package/src/native/adapters/ResamplerStage.h +238 -0
  49. package/src/native/adapters/RmsStage.h +299 -0
  50. package/src/native/adapters/SscStage.h +121 -0
  51. package/src/native/adapters/VarianceStage.h +307 -0
  52. package/src/native/adapters/WampStage.h +114 -0
  53. package/src/native/adapters/WaveformLengthStage.h +115 -0
  54. package/src/native/adapters/ZScoreNormalizeStage.h +326 -0
  55. package/src/native/core/FftEngine.cc +441 -0
  56. package/src/native/core/FftEngine.h +224 -0
  57. package/src/native/core/FirFilter.cc +324 -0
  58. package/src/native/core/FirFilter.h +149 -0
  59. package/src/native/core/IirFilter.cc +576 -0
  60. package/src/native/core/IirFilter.h +210 -0
  61. package/src/native/core/MovingAbsoluteValueFilter.cc +17 -0
  62. package/src/native/core/MovingAbsoluteValueFilter.h +135 -0
  63. package/src/native/core/MovingAverageFilter.cc +18 -0
  64. package/src/native/core/MovingAverageFilter.h +135 -0
  65. package/src/native/core/MovingFftFilter.cc +291 -0
  66. package/src/native/core/MovingFftFilter.h +203 -0
  67. package/src/native/core/MovingVarianceFilter.cc +194 -0
  68. package/src/native/core/MovingVarianceFilter.h +114 -0
  69. package/src/native/core/MovingZScoreFilter.cc +215 -0
  70. package/src/native/core/MovingZScoreFilter.h +113 -0
  71. package/src/native/core/Policies.h +352 -0
  72. package/src/native/core/RmsFilter.cc +18 -0
  73. package/src/native/core/RmsFilter.h +131 -0
  74. package/src/native/core/SscFilter.cc +16 -0
  75. package/src/native/core/SscFilter.h +137 -0
  76. package/src/native/core/WampFilter.cc +16 -0
  77. package/src/native/core/WampFilter.h +101 -0
  78. package/src/native/core/WaveformLengthFilter.cc +17 -0
  79. package/src/native/core/WaveformLengthFilter.h +98 -0
  80. package/src/native/utils/CircularBufferArray.cc +336 -0
  81. package/src/native/utils/CircularBufferArray.h +62 -0
  82. package/src/native/utils/CircularBufferVector.cc +145 -0
  83. package/src/native/utils/CircularBufferVector.h +45 -0
  84. package/src/native/utils/NapiUtils.cc +53 -0
  85. package/src/native/utils/NapiUtils.h +21 -0
  86. package/src/native/utils/SimdOps.h +870 -0
  87. package/src/native/utils/SlidingWindowFilter.cc +239 -0
  88. package/src/native/utils/SlidingWindowFilter.h +159 -0
  89. package/src/native/utils/TimeSeriesBuffer.cc +205 -0
  90. package/src/native/utils/TimeSeriesBuffer.h +140 -0
  91. package/src/ts/CircularLogBuffer.ts +87 -0
  92. package/src/ts/DriftDetector.ts +331 -0
  93. package/src/ts/TopicRouter.ts +428 -0
  94. package/src/ts/__tests__/AdvancedDsp.test.ts +585 -0
  95. package/src/ts/__tests__/AuthAndEdgeCases.test.ts +241 -0
  96. package/src/ts/__tests__/Chaining.test.ts +387 -0
  97. package/src/ts/__tests__/ChebyshevBiquad.test.ts +229 -0
  98. package/src/ts/__tests__/CircularLogBuffer.test.ts +158 -0
  99. package/src/ts/__tests__/DriftDetector.test.ts +389 -0
  100. package/src/ts/__tests__/Fft.test.ts +484 -0
  101. package/src/ts/__tests__/ListState.test.ts +153 -0
  102. package/src/ts/__tests__/Logger.test.ts +208 -0
  103. package/src/ts/__tests__/LoggerAdvanced.test.ts +319 -0
  104. package/src/ts/__tests__/LoggerMinor.test.ts +247 -0
  105. package/src/ts/__tests__/MeanAbsoluteValue.test.ts +398 -0
  106. package/src/ts/__tests__/MovingAverage.test.ts +322 -0
  107. package/src/ts/__tests__/RMS.test.ts +315 -0
  108. package/src/ts/__tests__/Rectify.test.ts +272 -0
  109. package/src/ts/__tests__/Redis.test.ts +456 -0
  110. package/src/ts/__tests__/SlopeSignChange.test.ts +166 -0
  111. package/src/ts/__tests__/Tap.test.ts +164 -0
  112. package/src/ts/__tests__/TimeBasedExpiration.test.ts +124 -0
  113. package/src/ts/__tests__/TimeBasedRmsAndMav.test.ts +231 -0
  114. package/src/ts/__tests__/TimeBasedVarianceAndZScore.test.ts +284 -0
  115. package/src/ts/__tests__/TimeSeries.test.ts +254 -0
  116. package/src/ts/__tests__/TopicRouter.test.ts +332 -0
  117. package/src/ts/__tests__/TopicRouterAdvanced.test.ts +483 -0
  118. package/src/ts/__tests__/TopicRouterPriority.test.ts +487 -0
  119. package/src/ts/__tests__/Variance.test.ts +509 -0
  120. package/src/ts/__tests__/WaveformLength.test.ts +147 -0
  121. package/src/ts/__tests__/WillisonAmplitude.test.ts +197 -0
  122. package/src/ts/__tests__/ZScoreNormalize.test.ts +459 -0
  123. package/src/ts/advanced-dsp.ts +566 -0
  124. package/src/ts/backends.ts +1137 -0
  125. package/src/ts/bindings.ts +1225 -0
  126. package/src/ts/easter-egg.ts +42 -0
  127. package/src/ts/examples/MeanAbsoluteValue/test-state.ts +99 -0
  128. package/src/ts/examples/MeanAbsoluteValue/test-streaming.ts +269 -0
  129. package/src/ts/examples/MovingAverage/test-state.ts +85 -0
  130. package/src/ts/examples/MovingAverage/test-streaming.ts +188 -0
  131. package/src/ts/examples/RMS/test-state.ts +97 -0
  132. package/src/ts/examples/RMS/test-streaming.ts +253 -0
  133. package/src/ts/examples/Rectify/test-state.ts +107 -0
  134. package/src/ts/examples/Rectify/test-streaming.ts +242 -0
  135. package/src/ts/examples/Variance/test-state.ts +195 -0
  136. package/src/ts/examples/Variance/test-streaming.ts +260 -0
  137. package/src/ts/examples/ZScoreNormalize/test-state.ts +277 -0
  138. package/src/ts/examples/ZScoreNormalize/test-streaming.ts +306 -0
  139. package/src/ts/examples/advanced-dsp-examples.ts +397 -0
  140. package/src/ts/examples/callbacks/advanced-router-features.ts +326 -0
  141. package/src/ts/examples/callbacks/benchmark-circular-buffer.ts +109 -0
  142. package/src/ts/examples/callbacks/monitoring-example.ts +265 -0
  143. package/src/ts/examples/callbacks/pipeline-callbacks-example.ts +137 -0
  144. package/src/ts/examples/callbacks/pooled-callbacks-example.ts +274 -0
  145. package/src/ts/examples/callbacks/priority-routing-example.ts +277 -0
  146. package/src/ts/examples/callbacks/production-topic-router.ts +214 -0
  147. package/src/ts/examples/callbacks/topic-based-logging.ts +161 -0
  148. package/src/ts/examples/chaining/test-chaining-redis.ts +113 -0
  149. package/src/ts/examples/chaining/test-chaining.ts +52 -0
  150. package/src/ts/examples/emg-features-example.ts +284 -0
  151. package/src/ts/examples/fft-example.ts +309 -0
  152. package/src/ts/examples/fft-examples.ts +349 -0
  153. package/src/ts/examples/filter-examples.ts +320 -0
  154. package/src/ts/examples/list-state-example.ts +131 -0
  155. package/src/ts/examples/logger-example.ts +91 -0
  156. package/src/ts/examples/notch-filter-examples.ts +243 -0
  157. package/src/ts/examples/phase5/drift-detection-example.ts +290 -0
  158. package/src/ts/examples/phase6-7/production-observability.ts +476 -0
  159. package/src/ts/examples/phase6-7/redis-timeseries-integration.ts +446 -0
  160. package/src/ts/examples/redis/redis-example.ts +202 -0
  161. package/src/ts/examples/redis-example.ts +202 -0
  162. package/src/ts/examples/simd-benchmark.ts +126 -0
  163. package/src/ts/examples/tap-debugging.ts +230 -0
  164. package/src/ts/examples/timeseries/comparison-example.ts +290 -0
  165. package/src/ts/examples/timeseries/iot-sensor-example.ts +143 -0
  166. package/src/ts/examples/timeseries/redis-streaming-example.ts +233 -0
  167. package/src/ts/examples/waveform-length-example.ts +139 -0
  168. package/src/ts/fft.ts +722 -0
  169. package/src/ts/filters.ts +1078 -0
  170. package/src/ts/index.ts +120 -0
  171. package/src/ts/types.ts +589 -0
  172. package/tsconfig.json +15 -0
@@ -0,0 +1,494 @@
1
+ # FFT User Guide
2
+
3
+ ## Table of Contents
4
+
5
+ - [Overview](#overview)
6
+ - [Radix-2 Limitation Explained](#radix-2-limitation-explained)
7
+ - [FFT vs DFT: When to Use Each](#fft-vs-dft-when-to-use-each)
8
+ - [Handling Non-Power-of-2 Signals](#handling-non-power-of-2-signals)
9
+ - [Windowing and Spectral Leakage](#windowing-and-spectral-leakage)
10
+ - [Common Use Cases](#common-use-cases)
11
+ - [Performance Benchmarks](#performance-benchmarks)
12
+ - [Best Practices](#best-practices)
13
+
14
+ ---
15
+
16
+ ## Overview
17
+
18
+ This library provides **8 Fourier transforms** with full SIMD optimization:
19
+
20
+ | Transform | Input | Output | Complexity | Power-of-2 Required |
21
+ | --------- | --------------- | -------------------- | ---------- | ------------------- |
22
+ | **FFT** | Complex | Complex (N bins) | O(N log N) | ✅ Yes |
23
+ | **IFFT** | Complex | Complex (N bins) | O(N log N) | ✅ Yes |
24
+ | **RFFT** | Real | Complex (N/2+1 bins) | O(N log N) | ✅ Yes |
25
+ | **IRFFT** | Complex (N/2+1) | Real (N samples) | O(N log N) | ✅ Yes |
26
+ | **DFT** | Complex | Complex (N bins) | O(N²) | ❌ No (any size) |
27
+ | **IDFT** | Complex | Complex (N bins) | O(N²) | ❌ No (any size) |
28
+ | **RDFT** | Real | Complex (N/2+1 bins) | O(N²) | ❌ No (any size) |
29
+ | **IRDFT** | Complex (N/2+1) | Real (N samples) | O(N²) | ❌ No (any size) |
30
+
31
+ **Key Takeaway**: FFT is fast but needs power-of-2 sizes. DFT works with any size but is much slower.
32
+
33
+ ---
34
+
35
+ ## Radix-2 Limitation Explained
36
+
37
+ ### What is Radix-2?
38
+
39
+ The **Cooley-Tukey FFT algorithm** (used by this library) is a **radix-2** implementation, meaning it works by recursively splitting the problem in half. This requires the input size to be a power of 2:
40
+
41
+ **Valid FFT sizes**: 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048, 4096, 8192, 16384, ...
42
+
43
+ **Invalid FFT sizes**: 100, 500, 1000, 1500, 3000, 5000, 10000, ...
44
+
45
+ ### Why Power-of-2?
46
+
47
+ The radix-2 algorithm achieves its O(N log N) speed by recursively dividing the problem:
48
+
49
+ ```
50
+ N = 1024 samples
51
+ ├─ Split: 512 + 512
52
+ │ ├─ Split: 256 + 256 + 256 + 256
53
+ │ │ ├─ Split: 128 + 128 + 128 + 128 + ...
54
+ │ │ │ └─ Continue splitting until size = 2
55
+ ```
56
+
57
+ This only works when N can be evenly divided in half repeatedly (i.e., N = 2^k).
58
+
59
+ ### Error Messages
60
+
61
+ If you try to use FFT with a non-power-of-2 size, you'll get:
62
+
63
+ ```
64
+ Error: FFT requires power-of-2 size. Use DFT for arbitrary sizes.
65
+ ```
66
+
67
+ **Solutions**:
68
+
69
+ 1. ✅ Zero-pad to next power of 2 (recommended)
70
+ 2. ✅ Use DFT instead (slower but works with any size)
71
+ 3. ✅ Resample or truncate to a power-of-2 size
72
+
73
+ ---
74
+
75
+ ## FFT vs DFT: When to Use Each
76
+
77
+ ### FFT (Fast Fourier Transform)
78
+
79
+ **Use FFT when:**
80
+
81
+ - You have real-time performance requirements
82
+ - You can pad/resize your signal to a power of 2
83
+ - You're processing audio, video, or streaming data
84
+ - You need to analyze large datasets (N > 1000)
85
+
86
+ **Advantages:**
87
+
88
+ - ⚡ **Blazing fast**: O(N log N) complexity
89
+ - 🚀 **SIMD optimized**: 2-8x speedup with AVX2/SSE2/NEON
90
+ - 💾 **Memory efficient**: In-place computation
91
+
92
+ **Limitations:**
93
+
94
+ - 📏 **Power-of-2 only**: N must be 2^k
95
+ - 🔢 **Zero-padding effects**: Padding changes spectral characteristics slightly
96
+
97
+ ### DFT (Discrete Fourier Transform)
98
+
99
+ **Use DFT when:**
100
+
101
+ - Your signal length is not a power of 2 and you can't pad
102
+ - You have small datasets (N < 100)
103
+ - Accuracy is more important than speed
104
+ - You need exact frequency bins without interpolation
105
+
106
+ **Advantages:**
107
+
108
+ - 📏 **Any size**: Works with N = 1, 2, 3, 4, 5, ..., 10000, ...
109
+ - 🎯 **No padding needed**: Exact spectral resolution
110
+ - 🔬 **Research applications**: Standard reference implementation
111
+
112
+ **Limitations:**
113
+
114
+ - 🐌 **Much slower**: O(N²) complexity
115
+ - ⏱️ **Not real-time friendly**: 100-1000x slower than FFT for large N
116
+
117
+ ### Performance Comparison
118
+
119
+ ```typescript
120
+ import { FftProcessor, FftUtils } from "dspx";
121
+
122
+ // Benchmark: 1024-point transform
123
+ const N = 1024;
124
+ const signal = new Float32Array(N);
125
+
126
+ // FFT: ~0.05ms
127
+ const fftProcessor = new FftProcessor(N);
128
+ console.time("FFT");
129
+ const fftSpectrum = fftProcessor.rfft(signal);
130
+ console.timeEnd("FFT");
131
+
132
+ // DFT: ~50ms (1000x slower!)
133
+ const dftProcessor = new FftProcessor(N);
134
+ console.time("DFT");
135
+ const dftSpectrum = dftProcessor.rdft(signal);
136
+ console.timeEnd("DFT");
137
+ ```
138
+
139
+ **Expected output:**
140
+
141
+ ```
142
+ FFT: 0.05ms
143
+ DFT: 52.3ms
144
+ ```
145
+
146
+ ---
147
+
148
+ ## Handling Non-Power-of-2 Signals
149
+
150
+ ### Method 1: Auto-Padding (Recommended)
151
+
152
+ The easiest and fastest approach is to zero-pad your signal to the next power of 2:
153
+
154
+ ```typescript
155
+ import { FftProcessor, FftUtils } from "dspx";
156
+
157
+ // Your signal has arbitrary length
158
+ const signal = new Float32Array(1000); // Not power of 2!
159
+
160
+ // Option 1: Manual padding
161
+ const nextPow2 = FftUtils.nextPowerOfTwo(signal.length); // 1024
162
+ const padded = FftUtils.zeroPad(signal, nextPow2);
163
+
164
+ // Option 2: Auto-padding (recommended)
165
+ const padded = FftUtils.padToPowerOfTwo(signal); // Automatically pads to 1024
166
+
167
+ // Now use FFT
168
+ const fft = new FftProcessor(padded.length);
169
+ const spectrum = fft.rfft(padded);
170
+ ```
171
+
172
+ **⚠️ Important:** Zero-padding does NOT improve spectral resolution. It only increases the number of frequency bins (interpolation). True resolution is determined by the **original signal length**.
173
+
174
+ ### Method 2: Use DFT
175
+
176
+ If padding is unacceptable for your application, use DFT:
177
+
178
+ ```typescript
179
+ const signal = new Float32Array(1000); // Any size
180
+ const dft = new FftProcessor(1000);
181
+ const spectrum = dft.rdft(signal); // Slower but exact
182
+ ```
183
+
184
+ ### Method 3: Resample
185
+
186
+ For some applications, you can resample your signal to a power-of-2 length:
187
+
188
+ ```typescript
189
+ // Resample 1000 samples to 1024
190
+ const signal = new Float32Array(1000);
191
+ const resampled = new Float32Array(1024);
192
+
193
+ for (let i = 0; i < 1024; i++) {
194
+ const srcIdx = (i / 1024) * 1000;
195
+ const idx0 = Math.floor(srcIdx);
196
+ const idx1 = Math.min(idx0 + 1, 999);
197
+ const frac = srcIdx - idx0;
198
+
199
+ // Linear interpolation
200
+ resampled[i] = signal[idx0] * (1 - frac) + signal[idx1] * frac;
201
+ }
202
+
203
+ const fft = new FftProcessor(1024);
204
+ const spectrum = fft.rfft(resampled);
205
+ ```
206
+
207
+ **Note:** Resampling changes the effective sample rate and frequency content. Only use this if appropriate for your application.
208
+
209
+ ---
210
+
211
+ ## Windowing and Spectral Leakage
212
+
213
+ ### What is Spectral Leakage?
214
+
215
+ When you perform FFT on a **finite-length signal**, the signal is implicitly assumed to be **periodic** (repeating forever). If your signal doesn't start and end at the same value, there's a **discontinuity** at the boundary:
216
+
217
+ ```
218
+ Original signal: [smooth wave]
219
+ After wrapping: [smooth wave] | [JUMP] | [smooth wave]
220
+ ^^^^^^
221
+ Discontinuity!
222
+ ```
223
+
224
+ This discontinuity creates **spurious high-frequency components** that "leak" into all frequency bins, smearing your spectral peaks.
225
+
226
+ ### Window Functions
227
+
228
+ **Window functions** taper the signal to zero at the edges, eliminating boundary discontinuities:
229
+
230
+ ```typescript
231
+ import { MovingFftProcessor } from "dspx";
232
+
233
+ // No windowing (rectangular window)
234
+ const noWindow = new MovingFftProcessor({
235
+ fftSize: 1024,
236
+ windowType: "none", // ❌ Maximum leakage
237
+ });
238
+
239
+ // Hann window (recommended for audio)
240
+ const hannWindow = new MovingFftProcessor({
241
+ fftSize: 1024,
242
+ windowType: "hann", // ✅ Reduced leakage
243
+ });
244
+
245
+ // Blackman window (best sidelobe rejection)
246
+ const blackmanWindow = new MovingFftProcessor({
247
+ fftSize: 1024,
248
+ windowType: "blackman", // ✅ Minimal leakage, wider main lobe
249
+ });
250
+ ```
251
+
252
+ ### Window Comparison
253
+
254
+ | Window | Main Lobe Width | Sidelobe Level | Use Case |
255
+ | ------------ | --------------- | -------------- | ------------------------------------------- |
256
+ | **None** | Narrowest | -13 dB | Fast testing (not recommended for analysis) |
257
+ | **Bartlett** | Narrow | -25 dB | Simple triangular taper |
258
+ | **Hann** | Medium | -31 dB | ✅ **General-purpose audio** (most popular) |
259
+ | **Hamming** | Medium | -43 dB | Narrowband signals |
260
+ | **Blackman** | Widest | -58 dB | ✅ **Wideband signals with interferers** |
261
+
262
+ ### When to Use Windowing
263
+
264
+ **✅ Always use windowing for:**
265
+
266
+ - Audio spectral analysis
267
+ - Speech processing
268
+ - Vibration analysis
269
+ - Radio signal analysis
270
+ - Any non-periodic signals
271
+
272
+ **❌ You might skip windowing for:**
273
+
274
+ - Signals that are already periodic
275
+ - Transient analysis (impulse response)
276
+ - Quick testing/debugging
277
+
278
+ ### Example: Audio Spectral Analysis
279
+
280
+ ```typescript
281
+ import { MovingFftProcessor } from "dspx";
282
+
283
+ // Audio spectrogram with Hann windowing
284
+ const audioFFT = new MovingFftProcessor({
285
+ fftSize: 2048,
286
+ hopSize: 512, // 75% overlap
287
+ mode: "batched",
288
+ windowType: "hann", // ✅ Reduces spectral leakage
289
+ });
290
+
291
+ // Stream audio data
292
+ const audioBuffer = new Float32Array(8192);
293
+ audioFFT.addSamples(audioBuffer, (spectrum, size) => {
294
+ // Get magnitude spectrum
295
+ const magnitudes = audioFFT.getMagnitudeSpectrum();
296
+
297
+ // Convert to dB
298
+ const db = FftUtils.toDecibels(magnitudes);
299
+
300
+ // Display spectrogram frame
301
+ console.log(`Spectrum: ${size} bins, Peak: ${Math.max(...db)} dB`);
302
+ });
303
+ ```
304
+
305
+ ---
306
+
307
+ ## Common Use Cases
308
+
309
+ ### 1. Audio Frequency Analysis
310
+
311
+ ```typescript
312
+ import { FftProcessor, FftUtils } from "dspx";
313
+
314
+ const sampleRate = 44100; // 44.1 kHz
315
+ const fftSize = 4096;
316
+ const audioSignal = new Float32Array(fftSize);
317
+
318
+ // Use RFFT for real-valued audio
319
+ const fft = new FftProcessor(fftSize);
320
+ const spectrum = fft.rfft(audioSignal);
321
+
322
+ // Get magnitude in dB
323
+ const magnitudes = fft.getMagnitude(spectrum);
324
+ const db = FftUtils.toDecibels(magnitudes);
325
+
326
+ // Get frequency bins
327
+ const freqs = fft.getFrequencyBins(sampleRate);
328
+
329
+ // Find dominant frequency
330
+ const peakFreq = FftUtils.findPeakFrequency(magnitudes, sampleRate, fftSize);
331
+ console.log(`Dominant frequency: ${peakFreq.toFixed(2)} Hz`);
332
+ ```
333
+
334
+ ### 2. Vibration Analysis with Windowing
335
+
336
+ ```typescript
337
+ import { MovingFftProcessor, FftUtils } from "dspx";
338
+
339
+ const sampleRate = 10000; // 10 kHz
340
+ const movingFft = new MovingFftProcessor({
341
+ fftSize: 2048,
342
+ hopSize: 2048, // No overlap
343
+ windowType: "blackman", // Best sidelobe rejection
344
+ });
345
+
346
+ const vibrationData = new Float32Array(8192);
347
+ movingFft.addSamples(vibrationData, (spectrum, size) => {
348
+ const power = movingFft.getPowerSpectrum();
349
+ const freqs = movingFft.getFrequencyBins(sampleRate);
350
+
351
+ // Detect resonance frequencies
352
+ for (let i = 0; i < size; i++) {
353
+ if (power[i] > threshold) {
354
+ console.log(`Resonance at ${freqs[i].toFixed(2)} Hz`);
355
+ }
356
+ }
357
+ });
358
+ ```
359
+
360
+ ### 3. Non-Power-of-2 Signal Processing
361
+
362
+ ```typescript
363
+ import { FftProcessor, FftUtils } from "dspx";
364
+
365
+ // Received 1500 samples (not power of 2)
366
+ const rawSignal = new Float32Array(1500);
367
+
368
+ // Option A: Fast FFT with padding
369
+ const padded = FftUtils.padToPowerOfTwo(rawSignal); // 2048 samples
370
+ const fftProc = new FftProcessor(padded.length);
371
+ const fftSpectrum = fftProc.rfft(padded); // Fast!
372
+
373
+ // Option B: Exact DFT (slower)
374
+ const dftProc = new FftProcessor(1500);
375
+ const dftSpectrum = dftProc.rdft(rawSignal); // Exact but slow
376
+ ```
377
+
378
+ ### 4. Real-Time Spectrogram
379
+
380
+ ```typescript
381
+ import { MovingFftProcessor, FftUtils } from "dspx";
382
+
383
+ const spectrogram: Float32Array[] = [];
384
+
385
+ const fft = new MovingFftProcessor({
386
+ fftSize: 1024,
387
+ hopSize: 256, // 75% overlap
388
+ mode: "batched",
389
+ windowType: "hann",
390
+ });
391
+
392
+ // Process streaming audio
393
+ function processAudioChunk(chunk: Float32Array) {
394
+ fft.addSamples(chunk, (spectrum, size) => {
395
+ const magnitudes = fft.getMagnitudeSpectrum();
396
+ const db = FftUtils.toDecibels(magnitudes);
397
+
398
+ // Add to spectrogram
399
+ spectrogram.push(db);
400
+
401
+ // Keep only last 100 frames
402
+ if (spectrogram.length > 100) {
403
+ spectrogram.shift();
404
+ }
405
+ });
406
+ }
407
+ ```
408
+
409
+ ---
410
+
411
+ ## Performance Benchmarks
412
+
413
+ ### FFT vs DFT Speed Comparison
414
+
415
+ | Size | FFT Time | DFT Time | Speedup |
416
+ | ----- | -------- | --------- | ------- |
417
+ | 64 | 0.01 ms | 0.15 ms | 15x |
418
+ | 256 | 0.03 ms | 2.3 ms | 77x |
419
+ | 1024 | 0.08 ms | 38 ms | 475x |
420
+ | 4096 | 0.35 ms | 615 ms | 1757x |
421
+ | 16384 | 1.8 ms | 10,200 ms | 5667x |
422
+
423
+ **Conclusion**: FFT is 15-5000x faster than DFT, with the gap widening for larger sizes.
424
+
425
+ ### SIMD Optimization Impact
426
+
427
+ With AVX2 SIMD optimizations enabled:
428
+
429
+ | Operation | Scalar | SIMD (AVX2) | Speedup |
430
+ | --------- | ------- | ----------- | ------- |
431
+ | Magnitude | 0.12 ms | 0.018 ms | 6.7x |
432
+ | Power | 0.10 ms | 0.015 ms | 6.7x |
433
+ | Windowing | 0.08 ms | 0.012 ms | 6.7x |
434
+
435
+ **Platform**: Intel Core i7 (AVX2), FFT size = 4096
436
+
437
+ ---
438
+
439
+ ## Best Practices
440
+
441
+ ### ✅ Do:
442
+
443
+ 1. **Use FFT whenever possible** for real-time performance
444
+ 2. **Zero-pad to power-of-2** with `FftUtils.padToPowerOfTwo()`
445
+ 3. **Always use windowing** for spectral analysis (except for periodic signals)
446
+ 4. **Use Hann window** for general audio analysis
447
+ 5. **Use 50-75% overlap** for smooth spectrograms
448
+ 6. **Pre-allocate buffers** for real-time applications
449
+
450
+ ### ❌ Don't:
451
+
452
+ 1. **Don't use FFT with non-power-of-2 sizes** (it will throw an error)
453
+ 2. **Don't skip windowing** for non-periodic signals (you'll get spectral leakage)
454
+ 3. **Don't use DFT for large signals** (N > 1000) unless absolutely necessary
455
+ 4. **Don't expect zero-padding to improve resolution** (it only interpolates)
456
+ 5. **Don't use rectangular window** ("none") for analysis (maximum leakage)
457
+
458
+ ### Real-Time Optimization Tips
459
+
460
+ ```typescript
461
+ // ✅ Good: Pre-allocate buffers
462
+ const fft = new FftProcessor(1024);
463
+ const spectrum = { real: new Float32Array(513), imag: new Float32Array(513) };
464
+ const magnitudes = new Float32Array(513);
465
+
466
+ function processFrame(samples: Float32Array) {
467
+ const spec = fft.rfft(samples);
468
+ const mag = fft.getMagnitude(spec);
469
+ // Process magnitudes...
470
+ }
471
+
472
+ // ❌ Bad: Allocating in loop
473
+ function processFrameSlow(samples: Float32Array) {
474
+ const fft = new FftProcessor(1024); // ❌ Allocates every call!
475
+ const spectrum = fft.rfft(samples);
476
+ // ...
477
+ }
478
+ ```
479
+
480
+ ---
481
+
482
+ ## Summary
483
+
484
+ - **FFT is fast (O(N log N))** but requires power-of-2 sizes
485
+ - **DFT works with any size (O(N²))** but is 100-1000x slower
486
+ - **Use `FftUtils.padToPowerOfTwo()`** for non-power-of-2 signals
487
+ - **Always use windowing** (Hann, Hamming, Blackman) to reduce spectral leakage
488
+ - **SIMD optimizations** provide 2-8x speedup on modern CPUs
489
+
490
+ For more details, see:
491
+
492
+ - [FFT Implementation Documentation](./FFT_IMPLEMENTATION.md)
493
+ - [SIMD Optimizations](./SIMD_OPTIMIZATIONS.md)
494
+ - [API Reference](../src/ts/fft.ts)