dsp-collection 0.2.5 → 0.2.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +5 -2
- package/filter/SpecFilt.d.ts +10 -10
- package/filter/SpecFilt.js +98 -99
- package/math/Complex.d.ts +42 -42
- package/math/Complex.js +130 -130
- package/math/ComplexArray.d.ts +36 -36
- package/math/ComplexArray.js +170 -171
- package/math/MathUtils.d.ts +9 -7
- package/math/MathUtils.js +116 -82
- package/math/MutableComplex.d.ts +22 -22
- package/math/MutableComplex.js +64 -65
- package/math/NumApprox.d.ts +3 -3
- package/math/NumApprox.js +67 -68
- package/math/PolyReal.d.ts +13 -13
- package/math/PolyReal.js +226 -227
- package/package.json +11 -3
- package/signal/AdaptiveStft.d.ts +12 -12
- package/signal/AdaptiveStft.js +57 -58
- package/signal/Autocorrelation.d.ts +5 -5
- package/signal/Autocorrelation.js +53 -54
- package/signal/Dft.d.ts +9 -9
- package/signal/Dft.js +87 -88
- package/signal/EnvelopeDetection.d.ts +1 -1
- package/signal/EnvelopeDetection.js +9 -10
- package/signal/Fft.d.ts +9 -9
- package/signal/Fft.js +275 -276
- package/signal/Goertzel.d.ts +5 -5
- package/signal/Goertzel.js +48 -49
- package/signal/InstFreq.d.ts +8 -8
- package/signal/InstFreq.js +26 -27
- package/signal/PitchDetectionHarm.d.ts +26 -26
- package/signal/PitchDetectionHarm.js +68 -69
- package/signal/Resampling.d.ts +7 -7
- package/signal/Resampling.js +218 -219
- package/signal/WindowFunctions.d.ts +40 -40
- package/signal/WindowFunctions.js +194 -195
- package/utils/ArrayUtils.d.ts +9 -9
- package/utils/ArrayUtils.js +68 -69
- package/utils/DspUtils.d.ts +4 -2
- package/utils/DspUtils.js +12 -7
- package/utils/MiscUtils.d.ts +6 -6
- package/utils/MiscUtils.js +20 -21
- package/filter/SpecFilt.js.map +0 -1
- package/math/Complex.js.map +0 -1
- package/math/ComplexArray.js.map +0 -1
- package/math/MathUtils.js.map +0 -1
- package/math/MutableComplex.js.map +0 -1
- package/math/NumApprox.js.map +0 -1
- package/math/PolyReal.js.map +0 -1
- package/signal/AdaptiveStft.js.map +0 -1
- package/signal/Autocorrelation.js.map +0 -1
- package/signal/Dft.js.map +0 -1
- package/signal/EnvelopeDetection.js.map +0 -1
- package/signal/Fft.js.map +0 -1
- package/signal/Goertzel.js.map +0 -1
- package/signal/InstFreq.js.map +0 -1
- package/signal/PitchDetectionHarm.js.map +0 -1
- package/signal/Resampling.js.map +0 -1
- package/signal/WindowFunctions.js.map +0 -1
- package/utils/ArrayUtils.js.map +0 -1
- package/utils/DspUtils.js.map +0 -1
- package/utils/MiscUtils.js.map +0 -1
package/math/PolyReal.js
CHANGED
|
@@ -1,227 +1,226 @@
|
|
|
1
|
-
import MutableComplex from "./MutableComplex.js";
|
|
2
|
-
export function evaluateReal(a, x) {
|
|
3
|
-
if (a.length == 0) {
|
|
4
|
-
throw new Error("Zero length array.");
|
|
5
|
-
}
|
|
6
|
-
const n = a.length - 1;
|
|
7
|
-
let r = a[n];
|
|
8
|
-
for (let i = n - 1; i >= 0; i--) {
|
|
9
|
-
r *= x;
|
|
10
|
-
r += a[i];
|
|
11
|
-
}
|
|
12
|
-
return r;
|
|
13
|
-
}
|
|
14
|
-
export function evaluateComplex(a, x) {
|
|
15
|
-
if (a.length == 0) {
|
|
16
|
-
throw new Error("Zero length array.");
|
|
17
|
-
}
|
|
18
|
-
const n = a.length - 1;
|
|
19
|
-
const r = new MutableComplex(a[n]);
|
|
20
|
-
for (let i = n - 1; i >= 0; i--) {
|
|
21
|
-
r.mulBy(x);
|
|
22
|
-
r.addRealTo(a[i]);
|
|
23
|
-
}
|
|
24
|
-
return r;
|
|
25
|
-
}
|
|
26
|
-
export function expand(zeros) {
|
|
27
|
-
const n = zeros.length;
|
|
28
|
-
if (n == 0) {
|
|
29
|
-
return Float64Array.of(1);
|
|
30
|
-
}
|
|
31
|
-
let a = Float64Array.of(-zeros[0], 1);
|
|
32
|
-
for (let i = 1; i < n; i++) {
|
|
33
|
-
const a2 = Float64Array.of(-zeros[i], 1);
|
|
34
|
-
a = multiply(a, a2);
|
|
35
|
-
}
|
|
36
|
-
return a;
|
|
37
|
-
}
|
|
38
|
-
export function compareEqual(a1, a2, eps = 0) {
|
|
39
|
-
const n1 = a1.length - 1;
|
|
40
|
-
const n2 = a2.length - 1;
|
|
41
|
-
const n = Math.max(n1, n2);
|
|
42
|
-
for (let i = 0; i <= n; i++) {
|
|
43
|
-
const v1 = (i <= n1) ? a1[i] : 0;
|
|
44
|
-
const v2 = (i <= n2) ? a2[i] : 0;
|
|
45
|
-
if (Math.abs(v1 - v2) > eps) {
|
|
46
|
-
return false;
|
|
47
|
-
}
|
|
48
|
-
}
|
|
49
|
-
return true;
|
|
50
|
-
}
|
|
51
|
-
export function add(a1, a2, eps = 0) {
|
|
52
|
-
const n1 = a1.length - 1;
|
|
53
|
-
const n2 = a2.length - 1;
|
|
54
|
-
const n3 = Math.max(n1, n2);
|
|
55
|
-
const a3 = new Float64Array(n3 + 1);
|
|
56
|
-
for (let i = 0; i <= n3; i++) {
|
|
57
|
-
const v1 = (i <= n1) ? a1[i] : 0;
|
|
58
|
-
const v2 = (i <= n2) ? a2[i] : 0;
|
|
59
|
-
a3[i] = v1 + v2;
|
|
60
|
-
}
|
|
61
|
-
return trim(a3, eps);
|
|
62
|
-
}
|
|
63
|
-
export function multiply(a1, a2, eps = 0) {
|
|
64
|
-
if (a1.length == 0 || a2.length == 0) {
|
|
65
|
-
throw new Error("Zero length arrays.");
|
|
66
|
-
}
|
|
67
|
-
if (a1.length == 1 && a1[0] == 0 || a2.length == 1 && a2[0] == 0) {
|
|
68
|
-
return Float64Array.of(0);
|
|
69
|
-
}
|
|
70
|
-
const n1 = a1.length - 1;
|
|
71
|
-
const n2 = a2.length - 1;
|
|
72
|
-
const n3 = n1 + n2;
|
|
73
|
-
const a3 = new Float64Array(n3 + 1);
|
|
74
|
-
for (let i = 0; i <= n3; i++) {
|
|
75
|
-
let t = 0;
|
|
76
|
-
const p1 = Math.max(0, i - n2);
|
|
77
|
-
const p2 = Math.min(n1, i);
|
|
78
|
-
for (let j = p1; j <= p2; j++) {
|
|
79
|
-
t += a1[j] * a2[i - j];
|
|
80
|
-
}
|
|
81
|
-
a3[i] = t;
|
|
82
|
-
}
|
|
83
|
-
return trim(a3, eps);
|
|
84
|
-
}
|
|
85
|
-
export function divide(a1r, a2r, eps = 0) {
|
|
86
|
-
if (a1r.length == 0 || a2r.length == 0) {
|
|
87
|
-
throw new Error("Zero length arrays.");
|
|
88
|
-
}
|
|
89
|
-
const a1 = trim(a1r, eps);
|
|
90
|
-
const a2 = trim(a2r, eps);
|
|
91
|
-
if (a2.length == 1) {
|
|
92
|
-
if (a2[0] == 0) {
|
|
93
|
-
throw new Error("Polynomial division by zero.");
|
|
94
|
-
}
|
|
95
|
-
if (a2[0] == 1) {
|
|
96
|
-
return [Float64Array.from(a1), Float64Array.of(0)];
|
|
97
|
-
}
|
|
98
|
-
return [divByReal(a1, a2[0]), Float64Array.of(0)];
|
|
99
|
-
}
|
|
100
|
-
const n1 = a1.length - 1;
|
|
101
|
-
const n2 = a2.length - 1;
|
|
102
|
-
if (n1 < n2) {
|
|
103
|
-
return [Float64Array.of(0), Float64Array.from(a1)];
|
|
104
|
-
}
|
|
105
|
-
const a = Float64Array.from(a1);
|
|
106
|
-
const lc2 = a2[n2];
|
|
107
|
-
for (let i = n1 - n2; i >= 0; i--) {
|
|
108
|
-
const r = a[n2 + i] / lc2;
|
|
109
|
-
a[n2 + i] = r;
|
|
110
|
-
for (let j = 0; j < n2; ++j) {
|
|
111
|
-
a[i + j] -= r * a2[j];
|
|
112
|
-
}
|
|
113
|
-
}
|
|
114
|
-
const quotient = trim(a.subarray(n2), eps);
|
|
115
|
-
const remainder = trim(a.subarray(0, n2), eps);
|
|
116
|
-
return [quotient, remainder];
|
|
117
|
-
}
|
|
118
|
-
export function gcd(a1, a2, eps = 0) {
|
|
119
|
-
let r1 = trim(a1, eps);
|
|
120
|
-
let r2 = trim(a2, eps);
|
|
121
|
-
makeMonic(r1);
|
|
122
|
-
makeMonic(r2);
|
|
123
|
-
if (r1.length < r2.length) {
|
|
124
|
-
[r1, r2] = [r2, r1];
|
|
125
|
-
}
|
|
126
|
-
while (true) {
|
|
127
|
-
if (r2.length < 2) {
|
|
128
|
-
return Float64Array.of(1);
|
|
129
|
-
}
|
|
130
|
-
const r = divide(r1, r2, eps)[1];
|
|
131
|
-
if (r.length == 1 && r[0] == 0) {
|
|
132
|
-
return r2;
|
|
133
|
-
}
|
|
134
|
-
makeMonic(r);
|
|
135
|
-
r1 = r2;
|
|
136
|
-
r2 = r;
|
|
137
|
-
}
|
|
138
|
-
}
|
|
139
|
-
function trim(a, eps = 0) {
|
|
140
|
-
if (a.length == 0) {
|
|
141
|
-
throw new Error("Zero length array.");
|
|
142
|
-
}
|
|
143
|
-
if (Math.abs(a[a.length - 1]) > eps) {
|
|
144
|
-
return Float64Array.from(a);
|
|
145
|
-
}
|
|
146
|
-
let len = a.length - 1;
|
|
147
|
-
while (len > 0 && Math.abs(a[len - 1]) <= eps) {
|
|
148
|
-
len--;
|
|
149
|
-
}
|
|
150
|
-
if (len == 0) {
|
|
151
|
-
return Float64Array.of(0);
|
|
152
|
-
}
|
|
153
|
-
const a2 = new Float64Array(len);
|
|
154
|
-
for (let i = 0; i < len; i++) {
|
|
155
|
-
a2[i] = a[i];
|
|
156
|
-
}
|
|
157
|
-
return a2;
|
|
158
|
-
}
|
|
159
|
-
function makeMonic(a) {
|
|
160
|
-
const len = a.length;
|
|
161
|
-
if (len == 0) {
|
|
162
|
-
throw new Error("Zero length array.");
|
|
163
|
-
}
|
|
164
|
-
const lc = a[len - 1];
|
|
165
|
-
if (lc == 1) {
|
|
166
|
-
return;
|
|
167
|
-
}
|
|
168
|
-
if (lc == 0) {
|
|
169
|
-
throw new Error("Leading coefficient is zero.");
|
|
170
|
-
}
|
|
171
|
-
a[len - 1] = 1;
|
|
172
|
-
for (let i = 0; i < len - 1; i++) {
|
|
173
|
-
a[i] /= lc;
|
|
174
|
-
}
|
|
175
|
-
}
|
|
176
|
-
function divByReal(a, b) {
|
|
177
|
-
const a2 = new Float64Array(a.length);
|
|
178
|
-
for (let i = 0; i < a.length; i++) {
|
|
179
|
-
a2[i] = a[i] / b;
|
|
180
|
-
}
|
|
181
|
-
return a2;
|
|
182
|
-
}
|
|
183
|
-
function divByRealInPlace(a, b) {
|
|
184
|
-
for (let i = 0; i < a.length; i++) {
|
|
185
|
-
a[i] /= b;
|
|
186
|
-
}
|
|
187
|
-
}
|
|
188
|
-
export function evaluateFractionComplex(f, x) {
|
|
189
|
-
const v1 = evaluateComplex(f[0], x);
|
|
190
|
-
const v2 = evaluateComplex(f[1], x);
|
|
191
|
-
return v1.div(v2);
|
|
192
|
-
}
|
|
193
|
-
export function addFractions(f1, f2, eps = 0) {
|
|
194
|
-
if (compareEqual(f1[1], f2[1], eps)) {
|
|
195
|
-
return [add(f1[0], f2[0], eps), Float64Array.from(f1[1])];
|
|
196
|
-
}
|
|
197
|
-
const g = gcd(f1[1], f2[1], eps);
|
|
198
|
-
if (g.length == 1 && g[0] == 1) {
|
|
199
|
-
const top = add(multiply(f1[0], f2[1], eps), multiply(f2[0], f1[1], eps));
|
|
200
|
-
const bottom = multiply(f1[1], f2[1], eps);
|
|
201
|
-
return [top, bottom];
|
|
202
|
-
}
|
|
203
|
-
const q1 = divide(f1[1], g, eps);
|
|
204
|
-
const q2 = divide(f2[1], g, eps);
|
|
205
|
-
const m1 = q1[0];
|
|
206
|
-
const m2 = q2[0];
|
|
207
|
-
const top = add(multiply(f1[0], m2, eps), multiply(f2[0], m1, eps));
|
|
208
|
-
const bottom = multiply(f1[1], m2, eps);
|
|
209
|
-
return [top, bottom];
|
|
210
|
-
}
|
|
211
|
-
export function multiplyFractions(f1, f2, eps = 0) {
|
|
212
|
-
const top = multiply(f1[0], f2[0], eps);
|
|
213
|
-
const bottom = multiply(f1[1], f2[1], eps);
|
|
214
|
-
return [top, bottom];
|
|
215
|
-
}
|
|
216
|
-
export function normalizeFraction(f, eps = 0) {
|
|
217
|
-
const top = trim(f[0], eps);
|
|
218
|
-
const bottom = trim(f[1], eps);
|
|
219
|
-
const lc = bottom[bottom.length - 1];
|
|
220
|
-
if (lc == 0) {
|
|
221
|
-
throw new Error("Fraction denominator is zero.");
|
|
222
|
-
}
|
|
223
|
-
divByRealInPlace(top, lc);
|
|
224
|
-
divByRealInPlace(bottom, lc);
|
|
225
|
-
return [top, bottom];
|
|
226
|
-
}
|
|
227
|
-
//# sourceMappingURL=PolyReal.js.map
|
|
1
|
+
import MutableComplex from "./MutableComplex.js";
|
|
2
|
+
export function evaluateReal(a, x) {
|
|
3
|
+
if (a.length == 0) {
|
|
4
|
+
throw new Error("Zero length array.");
|
|
5
|
+
}
|
|
6
|
+
const n = a.length - 1;
|
|
7
|
+
let r = a[n];
|
|
8
|
+
for (let i = n - 1; i >= 0; i--) {
|
|
9
|
+
r *= x;
|
|
10
|
+
r += a[i];
|
|
11
|
+
}
|
|
12
|
+
return r;
|
|
13
|
+
}
|
|
14
|
+
export function evaluateComplex(a, x) {
|
|
15
|
+
if (a.length == 0) {
|
|
16
|
+
throw new Error("Zero length array.");
|
|
17
|
+
}
|
|
18
|
+
const n = a.length - 1;
|
|
19
|
+
const r = new MutableComplex(a[n]);
|
|
20
|
+
for (let i = n - 1; i >= 0; i--) {
|
|
21
|
+
r.mulBy(x);
|
|
22
|
+
r.addRealTo(a[i]);
|
|
23
|
+
}
|
|
24
|
+
return r;
|
|
25
|
+
}
|
|
26
|
+
export function expand(zeros) {
|
|
27
|
+
const n = zeros.length;
|
|
28
|
+
if (n == 0) {
|
|
29
|
+
return Float64Array.of(1);
|
|
30
|
+
}
|
|
31
|
+
let a = Float64Array.of(-zeros[0], 1);
|
|
32
|
+
for (let i = 1; i < n; i++) {
|
|
33
|
+
const a2 = Float64Array.of(-zeros[i], 1);
|
|
34
|
+
a = multiply(a, a2);
|
|
35
|
+
}
|
|
36
|
+
return a;
|
|
37
|
+
}
|
|
38
|
+
export function compareEqual(a1, a2, eps = 0) {
|
|
39
|
+
const n1 = a1.length - 1;
|
|
40
|
+
const n2 = a2.length - 1;
|
|
41
|
+
const n = Math.max(n1, n2);
|
|
42
|
+
for (let i = 0; i <= n; i++) {
|
|
43
|
+
const v1 = (i <= n1) ? a1[i] : 0;
|
|
44
|
+
const v2 = (i <= n2) ? a2[i] : 0;
|
|
45
|
+
if (Math.abs(v1 - v2) > eps) {
|
|
46
|
+
return false;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
return true;
|
|
50
|
+
}
|
|
51
|
+
export function add(a1, a2, eps = 0) {
|
|
52
|
+
const n1 = a1.length - 1;
|
|
53
|
+
const n2 = a2.length - 1;
|
|
54
|
+
const n3 = Math.max(n1, n2);
|
|
55
|
+
const a3 = new Float64Array(n3 + 1);
|
|
56
|
+
for (let i = 0; i <= n3; i++) {
|
|
57
|
+
const v1 = (i <= n1) ? a1[i] : 0;
|
|
58
|
+
const v2 = (i <= n2) ? a2[i] : 0;
|
|
59
|
+
a3[i] = v1 + v2;
|
|
60
|
+
}
|
|
61
|
+
return trim(a3, eps);
|
|
62
|
+
}
|
|
63
|
+
export function multiply(a1, a2, eps = 0) {
|
|
64
|
+
if (a1.length == 0 || a2.length == 0) {
|
|
65
|
+
throw new Error("Zero length arrays.");
|
|
66
|
+
}
|
|
67
|
+
if (a1.length == 1 && a1[0] == 0 || a2.length == 1 && a2[0] == 0) {
|
|
68
|
+
return Float64Array.of(0);
|
|
69
|
+
}
|
|
70
|
+
const n1 = a1.length - 1;
|
|
71
|
+
const n2 = a2.length - 1;
|
|
72
|
+
const n3 = n1 + n2;
|
|
73
|
+
const a3 = new Float64Array(n3 + 1);
|
|
74
|
+
for (let i = 0; i <= n3; i++) {
|
|
75
|
+
let t = 0;
|
|
76
|
+
const p1 = Math.max(0, i - n2);
|
|
77
|
+
const p2 = Math.min(n1, i);
|
|
78
|
+
for (let j = p1; j <= p2; j++) {
|
|
79
|
+
t += a1[j] * a2[i - j];
|
|
80
|
+
}
|
|
81
|
+
a3[i] = t;
|
|
82
|
+
}
|
|
83
|
+
return trim(a3, eps);
|
|
84
|
+
}
|
|
85
|
+
export function divide(a1r, a2r, eps = 0) {
|
|
86
|
+
if (a1r.length == 0 || a2r.length == 0) {
|
|
87
|
+
throw new Error("Zero length arrays.");
|
|
88
|
+
}
|
|
89
|
+
const a1 = trim(a1r, eps);
|
|
90
|
+
const a2 = trim(a2r, eps);
|
|
91
|
+
if (a2.length == 1) {
|
|
92
|
+
if (a2[0] == 0) {
|
|
93
|
+
throw new Error("Polynomial division by zero.");
|
|
94
|
+
}
|
|
95
|
+
if (a2[0] == 1) {
|
|
96
|
+
return [Float64Array.from(a1), Float64Array.of(0)];
|
|
97
|
+
}
|
|
98
|
+
return [divByReal(a1, a2[0]), Float64Array.of(0)];
|
|
99
|
+
}
|
|
100
|
+
const n1 = a1.length - 1;
|
|
101
|
+
const n2 = a2.length - 1;
|
|
102
|
+
if (n1 < n2) {
|
|
103
|
+
return [Float64Array.of(0), Float64Array.from(a1)];
|
|
104
|
+
}
|
|
105
|
+
const a = Float64Array.from(a1);
|
|
106
|
+
const lc2 = a2[n2];
|
|
107
|
+
for (let i = n1 - n2; i >= 0; i--) {
|
|
108
|
+
const r = a[n2 + i] / lc2;
|
|
109
|
+
a[n2 + i] = r;
|
|
110
|
+
for (let j = 0; j < n2; ++j) {
|
|
111
|
+
a[i + j] -= r * a2[j];
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
const quotient = trim(a.subarray(n2), eps);
|
|
115
|
+
const remainder = trim(a.subarray(0, n2), eps);
|
|
116
|
+
return [quotient, remainder];
|
|
117
|
+
}
|
|
118
|
+
export function gcd(a1, a2, eps = 0) {
|
|
119
|
+
let r1 = trim(a1, eps);
|
|
120
|
+
let r2 = trim(a2, eps);
|
|
121
|
+
makeMonic(r1);
|
|
122
|
+
makeMonic(r2);
|
|
123
|
+
if (r1.length < r2.length) {
|
|
124
|
+
[r1, r2] = [r2, r1];
|
|
125
|
+
}
|
|
126
|
+
while (true) {
|
|
127
|
+
if (r2.length < 2) {
|
|
128
|
+
return Float64Array.of(1);
|
|
129
|
+
}
|
|
130
|
+
const r = divide(r1, r2, eps)[1];
|
|
131
|
+
if (r.length == 1 && r[0] == 0) {
|
|
132
|
+
return r2;
|
|
133
|
+
}
|
|
134
|
+
makeMonic(r);
|
|
135
|
+
r1 = r2;
|
|
136
|
+
r2 = r;
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
function trim(a, eps = 0) {
|
|
140
|
+
if (a.length == 0) {
|
|
141
|
+
throw new Error("Zero length array.");
|
|
142
|
+
}
|
|
143
|
+
if (Math.abs(a[a.length - 1]) > eps) {
|
|
144
|
+
return Float64Array.from(a);
|
|
145
|
+
}
|
|
146
|
+
let len = a.length - 1;
|
|
147
|
+
while (len > 0 && Math.abs(a[len - 1]) <= eps) {
|
|
148
|
+
len--;
|
|
149
|
+
}
|
|
150
|
+
if (len == 0) {
|
|
151
|
+
return Float64Array.of(0);
|
|
152
|
+
}
|
|
153
|
+
const a2 = new Float64Array(len);
|
|
154
|
+
for (let i = 0; i < len; i++) {
|
|
155
|
+
a2[i] = a[i];
|
|
156
|
+
}
|
|
157
|
+
return a2;
|
|
158
|
+
}
|
|
159
|
+
function makeMonic(a) {
|
|
160
|
+
const len = a.length;
|
|
161
|
+
if (len == 0) {
|
|
162
|
+
throw new Error("Zero length array.");
|
|
163
|
+
}
|
|
164
|
+
const lc = a[len - 1];
|
|
165
|
+
if (lc == 1) {
|
|
166
|
+
return;
|
|
167
|
+
}
|
|
168
|
+
if (lc == 0) {
|
|
169
|
+
throw new Error("Leading coefficient is zero.");
|
|
170
|
+
}
|
|
171
|
+
a[len - 1] = 1;
|
|
172
|
+
for (let i = 0; i < len - 1; i++) {
|
|
173
|
+
a[i] /= lc;
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
function divByReal(a, b) {
|
|
177
|
+
const a2 = new Float64Array(a.length);
|
|
178
|
+
for (let i = 0; i < a.length; i++) {
|
|
179
|
+
a2[i] = a[i] / b;
|
|
180
|
+
}
|
|
181
|
+
return a2;
|
|
182
|
+
}
|
|
183
|
+
function divByRealInPlace(a, b) {
|
|
184
|
+
for (let i = 0; i < a.length; i++) {
|
|
185
|
+
a[i] /= b;
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
export function evaluateFractionComplex(f, x) {
|
|
189
|
+
const v1 = evaluateComplex(f[0], x);
|
|
190
|
+
const v2 = evaluateComplex(f[1], x);
|
|
191
|
+
return v1.div(v2);
|
|
192
|
+
}
|
|
193
|
+
export function addFractions(f1, f2, eps = 0) {
|
|
194
|
+
if (compareEqual(f1[1], f2[1], eps)) {
|
|
195
|
+
return [add(f1[0], f2[0], eps), Float64Array.from(f1[1])];
|
|
196
|
+
}
|
|
197
|
+
const g = gcd(f1[1], f2[1], eps);
|
|
198
|
+
if (g.length == 1 && g[0] == 1) {
|
|
199
|
+
const top = add(multiply(f1[0], f2[1], eps), multiply(f2[0], f1[1], eps));
|
|
200
|
+
const bottom = multiply(f1[1], f2[1], eps);
|
|
201
|
+
return [top, bottom];
|
|
202
|
+
}
|
|
203
|
+
const q1 = divide(f1[1], g, eps);
|
|
204
|
+
const q2 = divide(f2[1], g, eps);
|
|
205
|
+
const m1 = q1[0];
|
|
206
|
+
const m2 = q2[0];
|
|
207
|
+
const top = add(multiply(f1[0], m2, eps), multiply(f2[0], m1, eps));
|
|
208
|
+
const bottom = multiply(f1[1], m2, eps);
|
|
209
|
+
return [top, bottom];
|
|
210
|
+
}
|
|
211
|
+
export function multiplyFractions(f1, f2, eps = 0) {
|
|
212
|
+
const top = multiply(f1[0], f2[0], eps);
|
|
213
|
+
const bottom = multiply(f1[1], f2[1], eps);
|
|
214
|
+
return [top, bottom];
|
|
215
|
+
}
|
|
216
|
+
export function normalizeFraction(f, eps = 0) {
|
|
217
|
+
const top = trim(f[0], eps);
|
|
218
|
+
const bottom = trim(f[1], eps);
|
|
219
|
+
const lc = bottom[bottom.length - 1];
|
|
220
|
+
if (lc == 0) {
|
|
221
|
+
throw new Error("Fraction denominator is zero.");
|
|
222
|
+
}
|
|
223
|
+
divByRealInPlace(top, lc);
|
|
224
|
+
divByRealInPlace(bottom, lc);
|
|
225
|
+
return [top, bottom];
|
|
226
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dsp-collection",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.6",
|
|
4
4
|
"description": "A collection of JavaScript modules for digital signal processing (written in TypeScript)",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"DSP",
|
|
@@ -13,11 +13,16 @@
|
|
|
13
13
|
"Spectral filtering",
|
|
14
14
|
"Window functions",
|
|
15
15
|
"Instantaneous frequency",
|
|
16
|
-
"Pitch estimation"
|
|
16
|
+
"Pitch estimation",
|
|
17
|
+
"Simple moving average (SMA)",
|
|
18
|
+
"triangular moving average (TMA)"
|
|
17
19
|
],
|
|
18
20
|
"license": "MIT",
|
|
19
21
|
"homepage": "http://www.source-code.biz/dsp/js",
|
|
20
|
-
"repository":
|
|
22
|
+
"repository": {
|
|
23
|
+
"type": "git",
|
|
24
|
+
"url": "git+https://github.com/chdh/dsp-collection-js.git"
|
|
25
|
+
},
|
|
21
26
|
"contributors": [
|
|
22
27
|
{
|
|
23
28
|
"name": "Christian d'Heureuse",
|
|
@@ -32,5 +37,8 @@
|
|
|
32
37
|
"doPack": "cd dist && npm pack",
|
|
33
38
|
"doPublish": "cd dist && npm publish"
|
|
34
39
|
},
|
|
40
|
+
"devDependencies": {
|
|
41
|
+
"@types/node": "^22"
|
|
42
|
+
},
|
|
35
43
|
"type": "module"
|
|
36
44
|
}
|
package/signal/AdaptiveStft.d.ts
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
|
-
import Complex from "../math/Complex.
|
|
2
|
-
import * as WindowFunctions from "./WindowFunctions.
|
|
3
|
-
export interface ComponentResult {
|
|
4
|
-
component: Complex;
|
|
5
|
-
frequency: number;
|
|
6
|
-
windowStartPosition: number;
|
|
7
|
-
windowWidth: number;
|
|
8
|
-
}
|
|
9
|
-
export declare function getSingle_relWindow(samples: Float64Array | Float32Array, roughFrequency: number, roughWindowCenterPosition: number, relWindowWidth: number, windowFunction: WindowFunctions.WindowFunction | undefined): ComponentResult | undefined;
|
|
10
|
-
export declare function getSingle_maxWindow(samples: Float64Array | Float32Array, roughFrequency: number, roughWindowCenterPosition: number, maxWindowWidth: number, windowFunction: WindowFunctions.WindowFunction | undefined): ComponentResult | undefined;
|
|
11
|
-
export declare function getSingle(samples: Float64Array | Float32Array, roughFrequency: number, windowFunction: WindowFunctions.WindowFunction | undefined): Complex;
|
|
12
|
-
export declare function getHarmonicAmplitudes(samples: Float64Array | Float32Array, windowCenterPosition: number, f0: number, harmonics: number, relWindowWidth?: number, windowFunction?: typeof WindowFunctions.flatTopWindowNorm): Float64Array | undefined;
|
|
1
|
+
import Complex from "../math/Complex.ts";
|
|
2
|
+
import * as WindowFunctions from "./WindowFunctions.ts";
|
|
3
|
+
export interface ComponentResult {
|
|
4
|
+
component: Complex;
|
|
5
|
+
frequency: number;
|
|
6
|
+
windowStartPosition: number;
|
|
7
|
+
windowWidth: number;
|
|
8
|
+
}
|
|
9
|
+
export declare function getSingle_relWindow(samples: Float64Array | Float32Array, roughFrequency: number, roughWindowCenterPosition: number, relWindowWidth: number, windowFunction: WindowFunctions.WindowFunction | undefined): ComponentResult | undefined;
|
|
10
|
+
export declare function getSingle_maxWindow(samples: Float64Array | Float32Array, roughFrequency: number, roughWindowCenterPosition: number, maxWindowWidth: number, windowFunction: WindowFunctions.WindowFunction | undefined): ComponentResult | undefined;
|
|
11
|
+
export declare function getSingle(samples: Float64Array | Float32Array, roughFrequency: number, windowFunction: WindowFunctions.WindowFunction | undefined): Complex;
|
|
12
|
+
export declare function getHarmonicAmplitudes(samples: Float64Array | Float32Array, windowCenterPosition: number, f0: number, harmonics: number, relWindowWidth?: number, windowFunction?: typeof WindowFunctions.flatTopWindowNorm): Float64Array | undefined;
|
package/signal/AdaptiveStft.js
CHANGED
|
@@ -1,58 +1,57 @@
|
|
|
1
|
-
import Complex from "../math/Complex.js";
|
|
2
|
-
import * as Goertzel from "./Goertzel.js";
|
|
3
|
-
import * as WindowFunctions from "./WindowFunctions.js";
|
|
4
|
-
export function getSingle_relWindow(samples, roughFrequency, roughWindowCenterPosition, relWindowWidth, windowFunction) {
|
|
5
|
-
if (roughFrequency <= 0 || roughFrequency >= 0.5 || relWindowWidth < 1) {
|
|
6
|
-
return;
|
|
7
|
-
}
|
|
8
|
-
if (!Number.isInteger(relWindowWidth)) {
|
|
9
|
-
throw new Error("Parameter relWindowWidth is not an integer.");
|
|
10
|
-
}
|
|
11
|
-
const windowWidth = Math.round(relWindowWidth / roughFrequency);
|
|
12
|
-
const windowStartPosition = Math.round(roughWindowCenterPosition - windowWidth / 2);
|
|
13
|
-
if (windowStartPosition < 0 || windowStartPosition + windowWidth > samples.length) {
|
|
14
|
-
return;
|
|
15
|
-
}
|
|
16
|
-
const windowSamples = samples.subarray(windowStartPosition, windowStartPosition + windowWidth);
|
|
17
|
-
const windowedSamples = windowFunction ? WindowFunctions.applyWindow(windowSamples, windowFunction) : windowSamples;
|
|
18
|
-
const component0 = Goertzel.goertzelSingle(windowedSamples, relWindowWidth);
|
|
19
|
-
const componentNormalized = component0.mulReal(2 / windowWidth);
|
|
20
|
-
const componentPhaseAdjusted = (relWindowWidth % 2 == 1) ? componentNormalized.neg() : componentNormalized;
|
|
21
|
-
return {
|
|
22
|
-
component: componentPhaseAdjusted,
|
|
23
|
-
frequency: relWindowWidth / windowWidth,
|
|
24
|
-
windowStartPosition: windowStartPosition,
|
|
25
|
-
windowWidth: windowWidth
|
|
26
|
-
};
|
|
27
|
-
}
|
|
28
|
-
export function getSingle_maxWindow(samples, roughFrequency, roughWindowCenterPosition, maxWindowWidth, windowFunction) {
|
|
29
|
-
const relWindowWidth = Math.floor(maxWindowWidth * roughFrequency);
|
|
30
|
-
return getSingle_relWindow(samples, roughFrequency, roughWindowCenterPosition, relWindowWidth, windowFunction);
|
|
31
|
-
}
|
|
32
|
-
export function getSingle(samples, roughFrequency, windowFunction) {
|
|
33
|
-
const r = getSingle_maxWindow(samples, roughFrequency, samples.length / 2, samples.length, windowFunction);
|
|
34
|
-
return r ? r.component : Complex.NaN;
|
|
35
|
-
}
|
|
36
|
-
export function getHarmonicAmplitudes(samples, windowCenterPosition, f0, harmonics, relWindowWidth = 7, windowFunction = WindowFunctions.flatTopWindowNorm) {
|
|
37
|
-
if (!isFinite(f0) || f0 <= 0 || harmonics <= 0) {
|
|
38
|
-
return;
|
|
39
|
-
}
|
|
40
|
-
if (!Number.isInteger(relWindowWidth)) {
|
|
41
|
-
throw new Error("Parameter relWindowWidth is not an integer.");
|
|
42
|
-
}
|
|
43
|
-
const windowWidth = Math.round(relWindowWidth / f0);
|
|
44
|
-
const windowStartPosition = Math.round(windowCenterPosition - windowWidth / 2);
|
|
45
|
-
if (windowStartPosition < 0 || windowStartPosition + windowWidth > samples.length || windowWidth <= 0) {
|
|
46
|
-
return;
|
|
47
|
-
}
|
|
48
|
-
const windowSamples = samples.subarray(windowStartPosition, windowStartPosition + windowWidth);
|
|
49
|
-
const windowedSamples = WindowFunctions.applyWindow(windowSamples, windowFunction);
|
|
50
|
-
const amplitudes = new Float64Array(harmonics);
|
|
51
|
-
for (let harmonic = 1; harmonic <= harmonics; harmonic++) {
|
|
52
|
-
const c = Goertzel.goertzelSingle(windowedSamples, harmonic * relWindowWidth);
|
|
53
|
-
const amplitude = c.abs() * 2 / windowWidth;
|
|
54
|
-
amplitudes[harmonic - 1] = amplitude;
|
|
55
|
-
}
|
|
56
|
-
return amplitudes;
|
|
57
|
-
}
|
|
58
|
-
//# sourceMappingURL=AdaptiveStft.js.map
|
|
1
|
+
import Complex from "../math/Complex.js";
|
|
2
|
+
import * as Goertzel from "./Goertzel.js";
|
|
3
|
+
import * as WindowFunctions from "./WindowFunctions.js";
|
|
4
|
+
export function getSingle_relWindow(samples, roughFrequency, roughWindowCenterPosition, relWindowWidth, windowFunction) {
|
|
5
|
+
if (roughFrequency <= 0 || roughFrequency >= 0.5 || relWindowWidth < 1) {
|
|
6
|
+
return;
|
|
7
|
+
}
|
|
8
|
+
if (!Number.isInteger(relWindowWidth)) {
|
|
9
|
+
throw new Error("Parameter relWindowWidth is not an integer.");
|
|
10
|
+
}
|
|
11
|
+
const windowWidth = Math.round(relWindowWidth / roughFrequency);
|
|
12
|
+
const windowStartPosition = Math.round(roughWindowCenterPosition - windowWidth / 2);
|
|
13
|
+
if (windowStartPosition < 0 || windowStartPosition + windowWidth > samples.length) {
|
|
14
|
+
return;
|
|
15
|
+
}
|
|
16
|
+
const windowSamples = samples.subarray(windowStartPosition, windowStartPosition + windowWidth);
|
|
17
|
+
const windowedSamples = windowFunction ? WindowFunctions.applyWindow(windowSamples, windowFunction) : windowSamples;
|
|
18
|
+
const component0 = Goertzel.goertzelSingle(windowedSamples, relWindowWidth);
|
|
19
|
+
const componentNormalized = component0.mulReal(2 / windowWidth);
|
|
20
|
+
const componentPhaseAdjusted = (relWindowWidth % 2 == 1) ? componentNormalized.neg() : componentNormalized;
|
|
21
|
+
return {
|
|
22
|
+
component: componentPhaseAdjusted,
|
|
23
|
+
frequency: relWindowWidth / windowWidth,
|
|
24
|
+
windowStartPosition: windowStartPosition,
|
|
25
|
+
windowWidth: windowWidth
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
export function getSingle_maxWindow(samples, roughFrequency, roughWindowCenterPosition, maxWindowWidth, windowFunction) {
|
|
29
|
+
const relWindowWidth = Math.floor(maxWindowWidth * roughFrequency);
|
|
30
|
+
return getSingle_relWindow(samples, roughFrequency, roughWindowCenterPosition, relWindowWidth, windowFunction);
|
|
31
|
+
}
|
|
32
|
+
export function getSingle(samples, roughFrequency, windowFunction) {
|
|
33
|
+
const r = getSingle_maxWindow(samples, roughFrequency, samples.length / 2, samples.length, windowFunction);
|
|
34
|
+
return r ? r.component : Complex.NaN;
|
|
35
|
+
}
|
|
36
|
+
export function getHarmonicAmplitudes(samples, windowCenterPosition, f0, harmonics, relWindowWidth = 7, windowFunction = WindowFunctions.flatTopWindowNorm) {
|
|
37
|
+
if (!isFinite(f0) || f0 <= 0 || harmonics <= 0) {
|
|
38
|
+
return;
|
|
39
|
+
}
|
|
40
|
+
if (!Number.isInteger(relWindowWidth)) {
|
|
41
|
+
throw new Error("Parameter relWindowWidth is not an integer.");
|
|
42
|
+
}
|
|
43
|
+
const windowWidth = Math.round(relWindowWidth / f0);
|
|
44
|
+
const windowStartPosition = Math.round(windowCenterPosition - windowWidth / 2);
|
|
45
|
+
if (windowStartPosition < 0 || windowStartPosition + windowWidth > samples.length || windowWidth <= 0) {
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
48
|
+
const windowSamples = samples.subarray(windowStartPosition, windowStartPosition + windowWidth);
|
|
49
|
+
const windowedSamples = WindowFunctions.applyWindow(windowSamples, windowFunction);
|
|
50
|
+
const amplitudes = new Float64Array(harmonics);
|
|
51
|
+
for (let harmonic = 1; harmonic <= harmonics; harmonic++) {
|
|
52
|
+
const c = Goertzel.goertzelSingle(windowedSamples, harmonic * relWindowWidth);
|
|
53
|
+
const amplitude = c.abs() * 2 / windowWidth;
|
|
54
|
+
amplitudes[harmonic - 1] = amplitude;
|
|
55
|
+
}
|
|
56
|
+
return amplitudes;
|
|
57
|
+
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import * as WindowFunctions from "./WindowFunctions.
|
|
2
|
-
export declare function nonPeriodicAutocorrelationSingle(x: ArrayLike<number>, distance: number, compensate: boolean): number;
|
|
3
|
-
export declare function findNonPeriodicAutocorrelationMaximum(x: ArrayLike<number>, minDistance: number, maxDistance: number, fixedOverlapWidth: boolean): number;
|
|
4
|
-
export declare function nonPeriodicAutocorrelation(x: ArrayLike<number>, normalize: boolean): Float64Array;
|
|
5
|
-
export declare function windowedNonPeriodicAutocorrelation(x: ArrayLike<number>, windowFunction: WindowFunctions.WindowFunction, normalize: boolean): Float64Array;
|
|
1
|
+
import * as WindowFunctions from "./WindowFunctions.ts";
|
|
2
|
+
export declare function nonPeriodicAutocorrelationSingle(x: ArrayLike<number>, distance: number, compensate: boolean): number;
|
|
3
|
+
export declare function findNonPeriodicAutocorrelationMaximum(x: ArrayLike<number>, minDistance: number, maxDistance: number, fixedOverlapWidth: boolean): number;
|
|
4
|
+
export declare function nonPeriodicAutocorrelation(x: ArrayLike<number>, normalize: boolean): Float64Array;
|
|
5
|
+
export declare function windowedNonPeriodicAutocorrelation(x: ArrayLike<number>, windowFunction: WindowFunctions.WindowFunction, normalize: boolean): Float64Array;
|