dsp-collection
Version:
A collection of JavaScript modules for digital signal processing (written in TypeScript)
117 lines • 3.39 kB
JavaScript
export function fuzzyEquals(a, b, eps) {
if (!isFinite(a) || !isFinite(b)) {
return false;
}
if (a == b) {
return true;
}
const diff = Math.abs(a - b);
if (diff <= eps) {
return true;
}
const mag = Math.max(Math.abs(a), Math.abs(b));
return diff <= mag * eps;
}
export function isFuzzyInteger(i, eps) {
return Math.abs(i - Math.round(i)) <= eps;
}
export function isPowerOf2(i) {
if (!Number.isSafeInteger(i) || i < 1 || i > 0x40000000) {
return false;
}
return (i & (i - 1)) == 0;
}
export function getNextPowerOf2(x) {
if (!isFinite(x)) {
return NaN;
}
let n = 1;
while (n <= x) {
n *= 2;
}
return n;
}
export function floorLog2(x) {
if (x > 0x7FFFFFFF || x < 1) {
throw new Error("Argument is not a valid integer.");
}
return 31 - Math.clz32(x);
}
export function hyperbolicDecline(t, a, b) {
switch (b) {
case 1: {
return 1 / (1 + a * t);
}
case 0: {
return Math.exp(-a * t);
}
case -1: {
return Math.max(0, 1 - a * t);
}
default: {
return 1 / (1 + b * a * t) ** (1 / b);
}
}
}
export function simpleMovingAverage(a, windowWidth, shift = false) {
if (windowWidth < 2 || !Number.isSafeInteger(windowWidth)) {
throw new Error("Specified window width is not valid for SMA.");
}
const len = a.length;
const a2 = new Float64Array(len);
const halfWindowWidth = Math.floor(windowWidth / 2);
const posShift = (shift && windowWidth % 2 == 0) ? 1 : 0;
const extendedLen = len + halfWindowWidth;
let movingSum = 0;
let n = 0;
for (let p = 0; p < extendedLen; p++) {
if (p >= windowWidth) {
movingSum -= a[p - windowWidth];
n--;
}
if (p < len) {
movingSum += a[p];
n++;
}
const p2 = p - halfWindowWidth + posShift;
if (p2 >= 0 && p2 < len) {
a2[p2] = movingSum / n;
}
}
return a2;
}
export function triangularMovingAverage(a, windowWidth) {
if (windowWidth < 4 || !Number.isSafeInteger(windowWidth)) {
throw new Error("Specified window width is not valid for TMA.");
}
const w1 = Math.floor(windowWidth / 2);
const w2 = windowWidth - w1;
const a1 = simpleMovingAverage(a, w1);
const a2 = simpleMovingAverage(a1, w2, true);
return a2;
}
export function triangularMovingAverageRef(a, windowWidth) {
if (windowWidth < 4 || !Number.isSafeInteger(windowWidth)) {
throw new Error("Specified window width is not valid for TMA.");
}
const len = a.length;
const a2 = new Float64Array(len);
for (let p = 0; p < len; p++) {
a2[p] = computeTriangularAverageAt(a, p, windowWidth);
}
return a2;
}
function computeTriangularAverageAt(a, p, windowWidth) {
const len = a.length;
const p1 = Math.max(0, Math.ceil(p - windowWidth / 2 + 0.1));
const p2 = Math.min(len - 1, Math.floor(p + windowWidth / 2 - 0.1));
let sum = 0;
let weightSum = 0;
for (let i = p1; i <= p2; i++) {
const weight = 1 - Math.abs(i - p) / (windowWidth / 2);
sum += a[i] * weight;
weightSum += weight;
}
return sum / weightSum;
}
//# sourceMappingURL=MathUtils.js.map