1# timeseries-compressibility
3Interactive exploration of how compressible quantized time series are.
5The generating model is: i.i.d. Gaussian noise (std σ, measured in quantization
6steps) → FIR filter → optional additive uniform dither on [-½, ½) → round to
7integers. The app shows the filter (convolution kernel and frequency response,
8with cutoffs in Hz against a chosen sample rate), a window of the generated
9integer signal (stationary by default, with a play toggle to let it stream
10endlessly), and the measured compression of a block of the generated integers
11under nine methods — zlib, zstd, and an rANS entropy coder, each raw,
12delta-coded, and LPC-residual-coded — as bits per sample and as ratio against
13raw int16 storage. The predictor order and the block size are controls, so the
14measurement can be pushed from 10k to a million samples and LPC from order 1
15to 128. Each prefilter group also carries a hollow bar: the order-0 entropy of
16the stream being coded, the limit a per-sample entropy coder cannot beat, which
17ANS misses by 1–2% (its symbol table plus its own arithmetic loss).
19Alongside the measurements it plots a theoretical bits/sample R — the smaller
20of a spectral estimate and a rigorous one-sample ceiling:
22```
23R = min(Rspec, Rsamp)
24Rspec = ∫₀¹ ½ log₂( 2πe (S(f) + ν) ) df S(f) = σ²|H(f)|², ν = 1/12 (1/6 dithered)
25Rsamp = H( round(N(0, v) [+ U(-½,½) with dither]) ) v = σ² Σ h²
26```
28Rspec is the Zamir–Feder rate of the dithered quantizer counted per Fourier
29mode: the signal modes are independent Gaussians of variance S(f), and the
30i.i.d. roundoff(+dither) noise is Gaussianized per mode by the CLT, so it
31enters at its full variance ν — not at the entropy power 1/(2πe) an aligned
32scalar quantizer would charge (the lattice lives in the sample basis; a dead
33band inside a live process costs ≈0.25 bits/mode, not zero). At high SNR it
34reduces to the Kolmogorov rate ½log₂(2πe σ²) + ∫log₂|H| df. Where the whole
35process sits below the quantization step, Rspec bottoms out while the true
36rate collapses; subadditivity H(z) ≤ Σ H(zₙ) makes Rsamp — the exact marginal
37entropy of one stored sample — a true upper bound with the right collapse,
38and the min selects it exactly there. Monte-Carlo puts R within ~0.01–0.02
39bits/sample for v ≳ 0.25 (worst ~+0.03 at the branch crossover). LPC + ANS
40should approach R; probing where the approximation holds is the point.
42## Run it
44```sh
45npm install
46npm run dev
47```
49## Layout
51```
52src/model/ the latent source (fixed seeded randomness indexed by sample
53 position, convolved zero-phase with the kernel on demand),
54 FIR presets, and the theoretical-rate formula
55src/compress/ lossless codecs run in the browser: zlib (fflate), zstd (wasm),
56 ans.ts (a bit-identical port of simple_ans), and FLAC-style
57 integer LPC; borrowed from entropy-quantized-linear-transform
58src/worker/ the codecs run off the main thread on a debounced parameter set
59src/components/ controls, filter plots, signal canvas, compression chart
60scripts/ true_rate.py — Monte-Carlo ground truth for R (Gibbs over the
61 latent Gaussian given the observed integers, Rao-Blackwellized
62 next-sample pmf); the app prints the exact command to run.
63 Requires numpy only.
64```
66Every reported size round-trips through the decoder and includes whatever the
67decoder needs (ANS symbol table, LPC coefficients). The signal view and the
68compression block read the same fixed latent noise sequence — parameter changes
69transform the same underlying data rather than resampling it, and the first
70window shown is the start of the block that gets compressed.