UNPKG

dsp-collection

Version:

A collection of JavaScript modules for digital signal processing (written in TypeScript)

227 lines 6.24 kB
import MutableComplex from "./MutableComplex.js"; export function evaluateReal(a, x) { if (a.length == 0) { throw new Error("Zero length array."); } const n = a.length - 1; let r = a[n]; for (let i = n - 1; i >= 0; i--) { r *= x; r += a[i]; } return r; } export function evaluateComplex(a, x) { if (a.length == 0) { throw new Error("Zero length array."); } const n = a.length - 1; const r = new MutableComplex(a[n]); for (let i = n - 1; i >= 0; i--) { r.mulBy(x); r.addRealTo(a[i]); } return r; } export function expand(zeros) { const n = zeros.length; if (n == 0) { return Float64Array.of(1); } let a = Float64Array.of(-zeros[0], 1); for (let i = 1; i < n; i++) { const a2 = Float64Array.of(-zeros[i], 1); a = multiply(a, a2); } return a; } export function compareEqual(a1, a2, eps = 0) { const n1 = a1.length - 1; const n2 = a2.length - 1; const n = Math.max(n1, n2); for (let i = 0; i <= n; i++) { const v1 = (i <= n1) ? a1[i] : 0; const v2 = (i <= n2) ? a2[i] : 0; if (Math.abs(v1 - v2) > eps) { return false; } } return true; } export function add(a1, a2, eps = 0) { const n1 = a1.length - 1; const n2 = a2.length - 1; const n3 = Math.max(n1, n2); const a3 = new Float64Array(n3 + 1); for (let i = 0; i <= n3; i++) { const v1 = (i <= n1) ? a1[i] : 0; const v2 = (i <= n2) ? a2[i] : 0; a3[i] = v1 + v2; } return trim(a3, eps); } export function multiply(a1, a2, eps = 0) { if (a1.length == 0 || a2.length == 0) { throw new Error("Zero length arrays."); } if (a1.length == 1 && a1[0] == 0 || a2.length == 1 && a2[0] == 0) { return Float64Array.of(0); } const n1 = a1.length - 1; const n2 = a2.length - 1; const n3 = n1 + n2; const a3 = new Float64Array(n3 + 1); for (let i = 0; i <= n3; i++) { let t = 0; const p1 = Math.max(0, i - n2); const p2 = Math.min(n1, i); for (let j = p1; j <= p2; j++) { t += a1[j] * a2[i - j]; } a3[i] = t; } return trim(a3, eps); } export function divide(a1r, a2r, eps = 0) { if (a1r.length == 0 || a2r.length == 0) { throw new Error("Zero length arrays."); } const a1 = trim(a1r, eps); const a2 = trim(a2r, eps); if (a2.length == 1) { if (a2[0] == 0) { throw new Error("Polynomial division by zero."); } if (a2[0] == 1) { return [Float64Array.from(a1), Float64Array.of(0)]; } return [divByReal(a1, a2[0]), Float64Array.of(0)]; } const n1 = a1.length - 1; const n2 = a2.length - 1; if (n1 < n2) { return [Float64Array.of(0), Float64Array.from(a1)]; } const a = Float64Array.from(a1); const lc2 = a2[n2]; for (let i = n1 - n2; i >= 0; i--) { const r = a[n2 + i] / lc2; a[n2 + i] = r; for (let j = 0; j < n2; ++j) { a[i + j] -= r * a2[j]; } } const quotient = trim(a.subarray(n2), eps); const remainder = trim(a.subarray(0, n2), eps); return [quotient, remainder]; } export function gcd(a1, a2, eps = 0) { let r1 = trim(a1, eps); let r2 = trim(a2, eps); makeMonic(r1); makeMonic(r2); if (r1.length < r2.length) { [r1, r2] = [r2, r1]; } while (true) { if (r2.length < 2) { return Float64Array.of(1); } const r = divide(r1, r2, eps)[1]; if (r.length == 1 && r[0] == 0) { return r2; } makeMonic(r); r1 = r2; r2 = r; } } function trim(a, eps = 0) { if (a.length == 0) { throw new Error("Zero length array."); } if (Math.abs(a[a.length - 1]) > eps) { return Float64Array.from(a); } let len = a.length - 1; while (len > 0 && Math.abs(a[len - 1]) <= eps) { len--; } if (len == 0) { return Float64Array.of(0); } const a2 = new Float64Array(len); for (let i = 0; i < len; i++) { a2[i] = a[i]; } return a2; } function makeMonic(a) { const len = a.length; if (len == 0) { throw new Error("Zero length array."); } const lc = a[len - 1]; if (lc == 1) { return; } if (lc == 0) { throw new Error("Leading coefficient is zero."); } a[len - 1] = 1; for (let i = 0; i < len - 1; i++) { a[i] /= lc; } } function divByReal(a, b) { const a2 = new Float64Array(a.length); for (let i = 0; i < a.length; i++) { a2[i] = a[i] / b; } return a2; } function divByRealInPlace(a, b) { for (let i = 0; i < a.length; i++) { a[i] /= b; } } export function evaluateFractionComplex(f, x) { const v1 = evaluateComplex(f[0], x); const v2 = evaluateComplex(f[1], x); return v1.div(v2); } export function addFractions(f1, f2, eps = 0) { if (compareEqual(f1[1], f2[1], eps)) { return [add(f1[0], f2[0], eps), Float64Array.from(f1[1])]; } const g = gcd(f1[1], f2[1], eps); if (g.length == 1 && g[0] == 1) { const top = add(multiply(f1[0], f2[1], eps), multiply(f2[0], f1[1], eps)); const bottom = multiply(f1[1], f2[1], eps); return [top, bottom]; } const q1 = divide(f1[1], g, eps); const q2 = divide(f2[1], g, eps); const m1 = q1[0]; const m2 = q2[0]; const top = add(multiply(f1[0], m2, eps), multiply(f2[0], m1, eps)); const bottom = multiply(f1[1], m2, eps); return [top, bottom]; } export function multiplyFractions(f1, f2, eps = 0) { const top = multiply(f1[0], f2[0], eps); const bottom = multiply(f1[1], f2[1], eps); return [top, bottom]; } export function normalizeFraction(f, eps = 0) { const top = trim(f[0], eps); const bottom = trim(f[1], eps); const lc = bottom[bottom.length - 1]; if (lc == 0) { throw new Error("Fraction denominator is zero."); } divByRealInPlace(top, lc); divByRealInPlace(bottom, lc); return [top, bottom]; } //# sourceMappingURL=PolyReal.js.map