You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: readme.md
+92-15Lines changed: 92 additions & 15 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -281,59 +281,136 @@ Smoothing and denoising. All operate in-place: `fn(data, params) → data`.
281
281
282
282
### `onePole(data, params)`
283
283
284
-
Exponential moving average – the simplest IIR smoother. One multiply per sample, no overshoot. Difference equation: $y[n] = (1-a)\,x[n] + a\,y[n-1]$ where $a = e^{-2\pi f_c/f_s}$. Transfer function: $H(z) = (1-a)/(1-az^{-1})$. Params: `fc`, `fs`.
Boxcar average of last N samples. $h[n] = 1/N$ for $n = 0..N-1$, $H(z) = (1 - z^{-N})/(N(1 - z^{-1}))$. Excellent for removing periodic noise when N matches the period. Params: `memory`.
292
-
**Linear phase · FIR · N multiplies · nulls at multiples of fs/N**
303
+
Boxcar average of last N samples. Excellent for removing periodic noise when N matches the period. Params: `memory`.
304
+
**Linear phase · FIR · nulls at multiples of fs/N**
Exponential decay accumulator. $y[n] = \lambda\,y[n-1] + (1-\lambda)\,x[n]$. Same as onePole but parameterized by decay factor $\lambda$ (0–1) instead of cutoff frequency. Params: `lambda`.
321
+
Exponential decay accumulator. Same as onePole but parameterized by decay factor instead of cutoff. Params: `lambda` (0–1).
299
322
**1 multiply · IIR**
300
323
324
+
```js
325
+
leakyIntegrator(data, { lambda:0.95 })
326
+
```
327
+
301
328
<imgsrc="plot/leaky-integrator.svg">
302
329
303
-
### `median(data, params)`
330
+
<details><summary>Reference</summary>
331
+
332
+
$y[n] = \lambda\,y[n-1] + (1-\lambda)\,x[n]$
304
333
305
-
Nonlinear – replaces each sample with the median of its neighborhood. Removes impulse noise (clicks, pops, outliers) while preserving edges and steps. Used in click removal, sensor outlier rejection, image denoising. Params: `size`.
306
-
**Nonlinear · no formula · preserves edges · O(N log N) per sample**
334
+
**Use when**: running average, DC estimation, simple smoothing by decay factor.
335
+
</details>
307
336
308
337
### `savitzkyGolay(data, params)`
309
338
310
-
Polynomial fit to sliding window – smooths noise while preserving peak height, width, and shape. The standard in spectroscopy, chromatography, and any measurement where peak distortion matters. Also computes smooth derivatives. Savitzky & Golay (1964).[^sg] Params: `windowSize`, `degree`, `derivative`.
339
+
Polynomial fit to sliding window – smooths noise while preserving peak height, width, and shape. Also computes smooth derivatives. Savitzky & Golay (1964).[^sg] Params: `windowSize`, `degree`, `derivative`.
311
340
**FIR · linear phase · preserves moments up to degree**
312
341
313
342
[^sg]: A. Savitzky, M.J.E. Golay, "Smoothing and Differentiation of Data," *Analytical Chemistry*, 1964.
Recursive Gaussian approximation (Young-van Vliet). O(1) cost regardless of kernel size – when sigma=100, FIR needs 600+ taps; this uses 6 multiplies. Forward-backward pass for zero phase. Params: `sigma`.
359
+
Recursive Gaussian approximation (Young-van Vliet). O(1) cost regardless of kernel size – when sigma=100, FIR needs 600+ taps; this uses 6 multiplies. Forward-backward for zero phase. Params: `sigma`.
320
360
**IIR · zero phase (offline) · O(1) per sample**
321
361
362
+
```js
363
+
gaussianIir(data, { sigma:10 })
364
+
```
365
+
322
366
<imgsrc="plot/gaussian-iir.svg">
323
367
368
+
<details><summary>Reference</summary>
369
+
370
+
**Use when**: large-kernel Gaussian smoothing. **Not for**: exact Gaussian (this is an approximation), causal filtering.
371
+
</details>
372
+
373
+
### `dynamicSmoothing(data, params)`
374
+
375
+
Self-adjusting SVF – cutoff adapts to signal speed. Like oneEuro but at audio rate, for smoothing parameter changes without zipper noise. Params: `minFc`, `maxFc`, `sensitivity`, `fs`.
Nonlinear – replaces each sample with the median of its neighborhood. Removes impulse noise (clicks, pops, outliers) while preserving edges and steps. Params: `size`.
387
+
**Nonlinear · preserves edges · O(N log N) per sample**
388
+
389
+
```js
390
+
median(data, { size:5 })
391
+
```
392
+
393
+
<details><summary>Reference</summary>
394
+
395
+
**Use when**: impulse noise (clicks, pops, sensor outliers), edge-preserving denoising. **Not for**: frequency-selective filtering (no defined frequency response).
Adaptive lowpass – cutoff increases with signal speed. Smooth at rest, responsive when moving. Used for mouse/touch/gaze input, sensor fusion. Casiez et al. (2012).[^euro] Params: `minCutoff`, `beta`, `dCutoff`, `fs`.
401
+
Adaptive lowpass – cutoff increases with signal speed. Smooth at rest, responsive when moving. Casiez et al. (2012).[^euro] Params: `minCutoff`, `beta`, `dCutoff`, `fs`.
327
402
**Adaptive · 1st-order IIR with time-varying cutoff**
328
403
329
404
[^euro]: G. Casiez et al., "1€ Filter," *CHI*, 2012.
330
405
331
-
### `dynamicSmoothing(data, params)`
406
+
```js
407
+
oneEuro(data, { minCutoff:1, beta:0.007, fs:60 })
408
+
```
332
409
333
-
Self-adjusting SVF – cutoff adapts to signal speed. Like oneEuro but at audio rate, for smoothing parameter changes without zipper noise. Params: `minFc`, `maxFc`, `sensitivity`, `fs`.
334
-
**Adaptive · 2nd-order SVF with time-varying cutoff**
410
+
<details><summary>Reference</summary>
335
411
336
-
<imgsrc="plot/dynamic-smoothing.svg">
412
+
**Use when**: mouse/touch/gaze input, sensor fusion, any UI with jitter. **Not for**: audio-rate processing (use dynamicSmoothing).
0 commit comments