Skip to content

Commit fa4977c

Browse files
committed
Update readme.md
1 parent 71811c0 commit fa4977c

1 file changed

Lines changed: 30 additions & 36 deletions

File tree

readme.md

Lines changed: 30 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -27,19 +27,11 @@ onePole(block1, params) // state preserved
2727
onePole(block2, params) // seamless continuation
2828
```
2929

30-
```js
31-
// Design a filter, then apply it:
32-
import { butterworth, filter } from 'digital-filter'
33-
34-
let sos = butterworth(4, 1000, 44100) // 4th-order lowpass at 1 kHz
35-
filter(data, { coefs: sos }) // apply to data in-place
36-
```
37-
3830
```js
3931
// Individual imports:
4032
import nlms from 'digital-filter/adaptive/nlms.js'
4133

42-
// Cancel echo: feed far-end and microphone, get clean signal
34+
// Cancel echo: feed far-end and microphone arrays, get clean signal
4335
let params = { order: 512, mu: 0.5 }
4436
nlms(farEnd, microphone, params)
4537
let clean = params.error
@@ -49,16 +41,33 @@ let clean = params.error
4941
> For audio-domain filters (weighting, EQ, synth, measurement) see [audio-filter](https://github.com/audiojs/audio-filter).
5042
5143

52-
## Reading the plots
44+
## Intro
45+
46+
**What is a filter?** Takes an array of samples, outputs an array of samples. `output[i] = (input[i] + input[i-1] + input[i-2]) / 3` is a filter – it smooths out fast changes. That's a lowpass.
47+
48+
**What is frequency response?** Every filter passes some frequencies and cuts others. The plots show how much each frequency is kept (magnitude, in dB) and how much it's delayed (phase, in degrees). 0dB = unchanged, –3dB = half power.
49+
50+
**What is IIR vs FIR?** IIR uses feedback (output depends on previous output). Few multiplies, low latency, but can't do linear phase and can blow up. FIR has no feedback – always stable, linear phase possible, but needs many taps (100–1000+) for a sharp cutoff, which can tax on performance.
51+
52+
**What is SOS?** Second-Order Sections – an IIR filter split into a chain of biquads (2nd-order, 5 coefficients each). A 4th-order Butterworth = 2 biquads. All design functions in this library return SOS arrays. This avoids the precision loss that happens with high-order polynomials in float64.
53+
54+
**How to read the plots?** Four panels per filter. Top-left: magnitude (dB vs Hz). Top-right: phase (degrees vs Hz). Bottom-left: group delay (samples vs Hz) – flat means no distortion. Bottom-right: impulse response. Dashed line = cutoff $f_c$.
55+
56+
**How to design and apply a filter?** Design functions return coefficients (SOS array or Float64Array). Pass them to `filter()` to process data in-place. State persists in `params` between calls for block processing.
57+
58+
```js
59+
let sos = butterworth(4, 1000, 44100) // design: 4th-order lowpass at 1 kHz
60+
filter(data, { coefs: sos }) // apply: modifies data in-place
5361

54-
Each filter shows four panels.
55-
**Magnitude** (top-left) – how much of each frequency passes through, in dB. 0 dB = unchanged, –3 dB = half power (the conventional cutoff), –40 dB = 1%.
56-
**Phase** (top-right) – how much each frequency is delayed in degrees. Constant slope = linear phase = waveform preserved. **Group delay** (bottom-left) – the derivative of phase; shows delay variation across frequency in samples. Flat = no distortion.
57-
**Impulse response** (bottom-right) – the filter's output when fed a single 1-sample pulse; its "fingerprint."
62+
// seamless processing
63+
let params = { coefs: butterworth(4, 1000, 44100) }
64+
filter(block1, params) // state preserved
65+
filter(block2, params) // seamless continuation
66+
```
5867

59-
The formulas describe the filter's frequency response. $|H(j\omega)|^2$ is the squared magnitude as a function of analog frequency $\omega$ – it defines the shape of the passband/stopband. $H(z)$ is the digital transfer function – what the code computes per sample. $h[n]$ is the impulse response – the FIR coefficients directly.
68+
**How to read the plots?** Four panels per filter. Top-left: magnitude (dB vs Hz). Top-right: phase (degrees vs Hz). Bottom-left: group delay (samples vs Hz) – flat means no distortion. Bottom-right: impulse response. Dashed line = cutoff $f_c$.
6069

61-
The dashed vertical line marks the cutoff frequency $f_c$.
70+
**How to read the formulas?** $|H(j\omega)|^2$: how the analog prototype shapes magnitude. $H(z)$: what the code computes per sample. $h[n]$: the impulse response / FIR coefficients.
6271

6372

6473
## IIR
@@ -546,21 +555,15 @@ Analog prototype → digital SOS pipeline. `transform.polesSos(poles, fc, fs, ty
546555

547556
## FAQ
548557

549-
**What is a filter?** A system that takes samples in and produces samples out. It does something in time (averaging, delaying) that corresponds to something in frequency (passing, cutting, boosting). The **magnitude response** shows how much of each frequency passes through.
550-
551-
**What is the dB scale?** Logarithmic ratio. $\text{dB} = 20\log_{10}(\text{ratio})$. 0 dB = unchanged, –3 dB = half power (the conventional cutoff), –6 dB = half amplitude, –20 dB = 10%, –60 dB = 0.1%.
552-
553-
**What are phase and group delay?** Magnitude tells you *how much* passes, phase tells you *when* it arrives. If all frequencies are delayed equally the waveform is preserved (**linear phase**). **Group delay** measures the delay per frequency. Constant group delay = linear phase. FIR can have linear phase; IIR cannot.
554-
555-
**IIR vs FIR?** IIR uses feedback – efficient (5–20 multiplies), low latency, nonlinear phase, can be unstable. FIR has no feedback – always stable, linear phase possible, needs 100–1000+ taps. Use IIR for real-time, FIR for offline or when linear phase is required.
558+
**What does the dB scale mean?** $\text{dB} = 20\log_{10}(\text{ratio})$. 0 dB = unchanged, –3 dB = half power, –6 dB = half amplitude, –20 dB = 10%, –60 dB = 0.1%.
556559

557-
**What are biquads and SOS?** The biquad is a 2nd-order filter with 5 coefficients. Every higher-order IIR is a cascade of biquads (**second-order sections**). Direct form above order ~6 loses precision with float64; SOS doesn't. This library returns SOS arrays by default.
560+
**When does phase matter?** When waveform shape must be preserved: crossovers (drivers must sum correctly), biomedical (ECG/EEG morphology), communications (intersymbol interference). For EQ, phase is usually inaudible.
558561

559-
**What is the bilinear transform?** Maps analog filter prototypes to digital: $s = (2/T)(z-1)/(z+1)$. All IIR design functions prewarp automatically – the cutoff you specify is the cutoff you get.
562+
**What is the bilinear transform?** Maps analog prototypes to digital: $s = (2/T)(z-1)/(z+1)$. All IIR design functions prewarp automatically – the cutoff you specify is the cutoff you get.
560563

561-
**When is a filter unstable?** When poles move outside the unit circle. Causes: coefficient quantization (use SOS, not direct form), careless parameter changes (Q → 0), feedback gain too high. Check with `isStable(sos)`. FIR is always stable.
564+
**When can a filter become unstable?** When poles move outside the unit circle. Causes: coefficient quantization (use SOS, not direct form), Q approaching 0, feedback gain too high. Check with `isStable(sos)`. FIR is always stable.
562565

563-
**What is aliasing?** A digital system at sample rate $f_s$ can represent frequencies up to $f_s/2$ (Nyquist). Frequencies above Nyquist fold back as artifacts. `decimate` and `interpolate` handle anti-aliasing automatically.
566+
**What is aliasing?** Frequencies above $f_s/2$ (Nyquist) fold back as artifacts. `decimate` and `interpolate` handle anti-aliasing automatically.
564567

565568

566569
## Choosing a filter
@@ -638,15 +641,6 @@ let htx = raisedCosine(101, 0.35, 8, { root: true })
638641
let shaped = convolution(symbols, htx)
639642
```
640643

641-
### Block processing
642-
643-
All stateful filters persist state between calls:
644-
645-
```js
646-
let params = { coefs: butterworth(4, 1000, 44100) }
647-
filter(block1, params) // state persists
648-
filter(block2, params) // seamless
649-
```
650644

651645

652646
## Pitfalls

0 commit comments

Comments
 (0)