|
| 1 | +import { cos, sin, sqrt, abs, PI } from './_util.js' |
| 2 | + |
| 3 | +/** Generate a full window as Float64Array. */ |
| 4 | +export function generate (fn, N, ...params) { |
| 5 | + let w = new Float64Array(N) |
| 6 | + for (let i = 0; i < N; i++) w[i] = fn(i, N, ...params) |
| 7 | + return w |
| 8 | +} |
| 9 | + |
| 10 | +/** Apply window to a signal in-place. */ |
| 11 | +export function apply (signal, fn, ...params) { |
| 12 | + for (let i = 0, N = signal.length; i < N; i++) signal[i] *= fn(i, N, ...params) |
| 13 | + return signal |
| 14 | +} |
| 15 | + |
| 16 | +/** Equivalent noise bandwidth in frequency bins. Rectangular = 1.0, Hann ≈ 1.5. */ |
| 17 | +export function enbw (fn, N, ...params) { |
| 18 | + let s = 0, s2 = 0 |
| 19 | + for (let i = 0; i < N; i++) { let v = fn(i, N, ...params); s += v; s2 += v * v } |
| 20 | + return N * s2 / (s * s) |
| 21 | +} |
| 22 | + |
| 23 | +/** Worst-case amplitude error in dB when a tone falls between DFT bins. */ |
| 24 | +export function scallopLoss (fn, N, ...params) { |
| 25 | + let s = 0, re = 0, im = 0 |
| 26 | + for (let i = 0; i < N; i++) { let v = fn(i, N, ...params); s += v; re += v * cos(PI * i / N); im -= v * sin(PI * i / N) } |
| 27 | + return s === 0 ? Infinity : -20 * Math.log10(sqrt(re * re + im * im) / abs(s)) |
| 28 | +} |
| 29 | + |
| 30 | +/** COLA deviation. Returns max relative deviation from constant overlap-add sum; 0 = perfect. */ |
| 31 | +export function cola (fn, N, hop, ...params) { |
| 32 | + let win = generate(fn, N, ...params) |
| 33 | + let sums = new Float64Array(hop) |
| 34 | + for (let t = 0; t < hop; t++) for (let k = t; k < N; k += hop) sums[t] += win[k] |
| 35 | + let mean = 0 |
| 36 | + for (let t = 0; t < hop; t++) mean += sums[t] |
| 37 | + mean /= hop |
| 38 | + if (mean === 0) return Infinity |
| 39 | + let maxDev = 0 |
| 40 | + for (let t = 0; t < hop; t++) { let d = abs(sums[t] - mean) / mean; if (d > maxDev) maxDev = d } |
| 41 | + return maxDev |
| 42 | +} |
0 commit comments