dsp-filter-library
Version:
A comprehensive DSP library with 23 window functions, advanced FIR/IIR filter design, biquad combination, and interactive visualization
46 lines (44 loc) • 1.82 kB
JavaScript
// Digital filter response calculations
import { Cx } from "../core/Complex.js";
import { unwrapPhase } from "../core/util.js";
export class Response {
static H_w_IIR(sections,w){
const z1={re:Math.cos(w),im:-Math.sin(w)}, z2={re:Math.cos(2*w),im:-Math.sin(2*w)};
let acc={re:1,im:0};
for(const s of sections){
const [b0,b1,b2]=s.b, [,a1,a2]=s.a;
const num={re:b0+b1*z1.re+b2*z2.re, im:b1*z1.im+b2*z2.im};
const den={re:1+a1*z1.re+a2*z2.re, im:a1*z1.im+a2*z2.im};
const den2=den.re*den.re+den.im*den.im;
const h={re:(num.re*den.re+num.im*den.im)/den2, im:(num.im*den.re-num.re*den.im)/den2};
acc = Cx.mul(acc,h);
}
return acc;
}
static H_w_FIR(taps,w){
let re=0, im=0;
for(let n=0;n<taps.length;n++){ re += taps[n]*Math.cos(w*n); im -= taps[n]*Math.sin(w*n); }
return {re, im};
}
static magDbFromH(H){ return 20*Math.log10(Math.max(1e-16, Cx.abs(H))); }
static unwrapToDeg(phRad){ return unwrapPhase(phRad).map(v=>v*180/Math.PI); }
static groupDelay(phUnwrappedRad, w){
const N=w.length, gd=new Array(N).fill(0);
if(N>=3){
for(let i=1;i<N-1;i++){
const dphi=phUnwrappedRad[i+1]-phUnwrappedRad[i-1], dw=w[i+1]-w[i-1];
gd[i] = - dphi / (dw || 1e-12);
}
gd[0]=gd[1]; gd[N-1]=gd[N-2];
}
return gd;
}
static phaseDelay(phUnwrappedRad, w){
const pd=new Array(w.length).fill(0);
for(let i=0;i<w.length;i++) pd[i] = (w[i]===0 ? NaN : -phUnwrappedRad[i]/w[i]);
let firstFinite = pd.find(v=>Number.isFinite(v)); if(!Number.isFinite(firstFinite)) firstFinite=0;
for(let i=0;i<pd.length && !Number.isFinite(pd[i]); i++) pd[i]=firstFinite;
for(let i=1;i<pd.length;i++) if(!Number.isFinite(pd[i])) pd[i]=pd[i-1];
return pd;
}
}