dsp-filter-library
Version:
A comprehensive DSP library with 23 window functions, advanced FIR/IIR filter design, biquad combination, and interactive visualization
38 lines (35 loc) • 1.4 kB
JavaScript
// Second Order Sections
import { Cx } from "../core/Complex.js";
function pairConjs(arr){
const used=new Array(arr.length).fill(false), pairs=[];
for(let i=0;i<arr.length;i++){
if(used[i]) continue; const a=arr[i]; let matched=false;
for(let j=i+1;j<arr.length;j++) if(!used[j]){
const b=arr[j];
if(Math.abs(a.re-b.re)<1e-10 && Math.abs(a.im+b.im)<1e-10){
pairs.push([a,b]); used[i]=used[j]=true; matched=true; break;
}
}
if(!matched){ pairs.push([a]); used[i]=true; }
}
return pairs;
}
export class SOS {
static fromZPK(zZeros, zPoles, gain=1){
while(zZeros.length<zPoles.length) zZeros.push({re:-1,im:0});
const zp=pairConjs(zZeros), pp=pairConjs(zPoles);
const sections=[]; let zi=0, pi=0;
while(pi<pp.length){
const ppair=pp[pi++], zpair=(zi<zp.length)?zp[zi++]:[{re:-1,im:0},{re:-1,im:0}];
const p1=ppair[0], p2=ppair[1]||{re:0,im:0};
const z1=zpair[0], z2=zpair[1]||{re:-1,im:0};
const sumZ={re:z1.re+z2.re, im:z1.im+z2.im}, prodZ=Cx.mul(z1,z2);
const sumP={re:p1.re+p2.re, im:p1.im+p2.im}, prodP=Cx.mul(p1,p2);
const b=[1, -sumZ.re, prodZ.re];
const a=[1, -sumP.re, prodP.re];
sections.push({b,a});
}
if(sections.length) sections[0].b=[sections[0].b[0]*gain, sections[0].b[1]*gain, sections[0].b[2]*gain];
return sections;
}
}