|
1 | | -let { cos, sqrt, abs, PI } = Math |
| 1 | +// Windows come from window-function (scijs) — the canonical per-sample evaluators |
| 2 | +// (symmetric, N-1 denominator: scipy.signal.windows / Harris 1978 conventions). |
| 3 | +// This module only adapts them to FIR design's fill shape: name(N) → Float64Array. |
| 4 | +import { |
| 5 | + hamming as wfHamming, hann as wfHann, blackman as wfBlackman, |
| 6 | + blackmanHarris as wfBlackmanHarris, bartlett as wfBartlett, |
| 7 | + rectangular as wfRectangular, kaiser as wfKaiser, |
| 8 | +} from 'window-function' |
2 | 9 |
|
3 | | -// Symmetric (sym=true) window definitions, N-1 denominator — matches |
4 | | -// scipy.signal.windows / Harris 1978 "On the use of windows..." conventions. |
5 | | - |
6 | | -/** |
7 | | - * Hamming window. |
8 | | - * @param {number} N - Window length |
9 | | - * @returns {Float64Array} |
10 | | - */ |
11 | | -export function hamming (N) { |
| 10 | +const fill = (fn, N, ...args) => { |
12 | 11 | let w = new Float64Array(N) |
13 | | - for (let i = 0; i < N; i++) w[i] = 0.54 - 0.46 * cos(2 * PI * i / (N - 1)) |
| 12 | + for (let i = 0; i < N; i++) w[i] = fn(i, N, ...args) |
14 | 13 | return w |
15 | 14 | } |
16 | 15 |
|
17 | | -/** |
18 | | - * Hann window. |
19 | | - * @param {number} N |
20 | | - * @returns {Float64Array} |
21 | | - */ |
22 | | -export function hann (N) { |
23 | | - let w = new Float64Array(N) |
24 | | - for (let i = 0; i < N; i++) w[i] = 0.5 - 0.5 * cos(2 * PI * i / (N - 1)) |
25 | | - return w |
26 | | -} |
| 16 | +/** Hamming window. @param {number} N @returns {Float64Array} */ |
| 17 | +export const hamming = (N) => fill(wfHamming, N) |
27 | 18 |
|
28 | | -/** |
29 | | - * Blackman window (a0=0.42, a1=0.5, a2=0.08). |
30 | | - * @param {number} N |
31 | | - * @returns {Float64Array} |
32 | | - */ |
33 | | -export function blackman (N) { |
34 | | - let w = new Float64Array(N) |
35 | | - for (let i = 0; i < N; i++) { |
36 | | - let x = 2 * PI * i / (N - 1) |
37 | | - w[i] = 0.42 - 0.5 * cos(x) + 0.08 * cos(2 * x) |
38 | | - } |
39 | | - return w |
40 | | -} |
| 19 | +/** Hann window. @param {number} N @returns {Float64Array} */ |
| 20 | +export const hann = (N) => fill(wfHann, N) |
41 | 21 |
|
42 | | -/** |
43 | | - * 4-term Blackman-Harris window (-92 dB sidelobes). |
44 | | - * @param {number} N |
45 | | - * @returns {Float64Array} |
46 | | - */ |
47 | | -export function blackmanHarris (N) { |
48 | | - let w = new Float64Array(N) |
49 | | - for (let i = 0; i < N; i++) { |
50 | | - let x = 2 * PI * i / (N - 1) |
51 | | - w[i] = 0.35875 - 0.48829 * cos(x) + 0.14128 * cos(2 * x) - 0.01168 * cos(3 * x) |
52 | | - } |
53 | | - return w |
54 | | -} |
| 22 | +/** Blackman window (a0=0.42, a1=0.5, a2=0.08). @param {number} N @returns {Float64Array} */ |
| 23 | +export const blackman = (N) => fill(wfBlackman, N) |
55 | 24 |
|
56 | | -/** |
57 | | - * Bartlett (triangular, zero-ended) window. |
58 | | - * @param {number} N |
59 | | - * @returns {Float64Array} |
60 | | - */ |
61 | | -export function bartlett (N) { |
62 | | - let w = new Float64Array(N) |
63 | | - for (let i = 0; i < N; i++) w[i] = 1 - abs(2 * i / (N - 1) - 1) |
64 | | - return w |
65 | | -} |
| 25 | +/** 4-term Blackman-Harris window (−92 dB sidelobes). @param {number} N @returns {Float64Array} */ |
| 26 | +export const blackmanHarris = (N) => fill(wfBlackmanHarris, N) |
66 | 27 |
|
67 | | -/** |
68 | | - * Rectangular (boxcar) window. |
69 | | - * @param {number} N |
70 | | - * @returns {Float64Array} |
71 | | - */ |
72 | | -export function rectangular (N) { |
73 | | - return new Float64Array(N).fill(1) |
74 | | -} |
| 28 | +/** Bartlett (triangular, zero-ended) window. @param {number} N @returns {Float64Array} */ |
| 29 | +export const bartlett = (N) => fill(wfBartlett, N) |
| 30 | + |
| 31 | +/** Rectangular (boxcar) window. @param {number} N @returns {Float64Array} */ |
| 32 | +export const rectangular = (N) => fill(wfRectangular, N) |
75 | 33 |
|
76 | 34 | /** |
77 | | - * Kaiser window: I0(beta*sqrt(1-x^2))/I0(beta), x = 2i/(N-1) - 1. |
| 35 | + * Kaiser window: I0(beta·sqrt(1−x²))/I0(beta), x = 2i/(N−1) − 1. |
78 | 36 | * @param {number} N |
79 | | - * @param {number} beta - Shape parameter (0 = rectangular; ~0.1102*(A-8.7) for A dB stopband) |
| 37 | + * @param {number} beta - Shape parameter (0 = rectangular; ~0.1102·(A−8.7) for A dB stopband) |
80 | 38 | * @returns {Float64Array} |
81 | 39 | */ |
82 | | -export function kaiser (N, beta) { |
83 | | - let w = new Float64Array(N) |
84 | | - let denom = besselI0(beta) |
85 | | - for (let i = 0; i < N; i++) { |
86 | | - let x = 2 * i / (N - 1) - 1 |
87 | | - w[i] = besselI0(beta * sqrt(1 - x * x)) / denom |
88 | | - } |
89 | | - return w |
90 | | -} |
91 | | - |
92 | | -// Modified Bessel function of the first kind, order 0 (series expansion) |
93 | | -function besselI0 (x) { |
94 | | - let sum = 1, term = 1 |
95 | | - for (let k = 1; k < 50; k++) { |
96 | | - term *= (x / (2 * k)) * (x / (2 * k)) |
97 | | - sum += term |
98 | | - if (term < sum * 1e-16) break |
99 | | - } |
100 | | - return sum |
101 | | -} |
| 40 | +export const kaiser = (N, beta) => fill(wfKaiser, N, beta) |
102 | 41 |
|
103 | 42 | const WINDOWS = { |
104 | 43 | hamming, hann, hanning: hann, blackman, |
|
0 commit comments