Mercurial > hg > x
view SinEst.cpp @ 1:6422640a802f
first upload
author | Wen X <xue.wen@elec.qmul.ac.uk> |
---|---|
date | Tue, 05 Oct 2010 10:45:57 +0100 |
parents | |
children |
line wrap: on
line source
//--------------------------------------------------------------------------- #include <stddef.h> #include "SinEst.h" #include "fft.h" #include "opt.h" #include "SinSyn.h" #include "splines.h" #include "WindowFunctions.h" //--------------------------------------------------------------------------- /* function dsincd_unn: derivative of unnormalized discrete sinc function In: x, scale N Returns the derivative of sincd_unn(x, N) */ double dsincd_unn(double x, int N) { double r=0; double omg=M_PI*x; double domg=omg/N; if (fabs(x)>1e-6) { r=M_PI*(cos(omg)-sin(omg)*cos(domg)/sin(domg)/N)/sin(domg); } else { if (domg!=0) { double sindomg=sin(domg); r=-omg*omg*omg*(1-1.0/(1.0*N*N))/3*M_PI/N/sindomg/sindomg; } else r=0; } return r; }//dsincd_unn /* function ddsincd_unn: 2nd-order derivative of unnormalized discrete sinc function In: x, scale (equivalently, window size) N Returns the 2nd-order derivative of sincd_unn(x, N) */ double ddsincd_unn(double x, int N) { double r=0; double omg=M_PI*x; double domg=omg/N; double PI2=M_PI*M_PI; double NN=1.0/N/N-1; if (domg==0) { r=PI2*N*NN/3; } else { if (fabs(x)>1e-5) { r=sin(domg)*cos(omg)-sin(omg)*cos(domg)/N; } else { r=omg*omg*omg/N*NN/3; } double ss=sin(omg)*NN; r=-2.0/N*cos(domg)*r/sin(domg)/sin(domg)+ss; r=r*PI2/sin(domg); } return r; }//ddsincd_unn //--------------------------------------------------------------------------- /* function Window: calculates the cosine-family-windowed spectrum of a complex sinusoid on [0:N-1] at frequency f bins with zero central phase. In: f: frequency, in bins N: window size M, c[]: cosine-family window decomposition coefficients Out: x[0...K2-K1] containing the spectrum at bins K1, ..., K2. Returns pointer to x. x is created anew if x=0 is specified on start. */ cdouble* Window(cdouble* x, double f, int N, int M, double* c, int K1, int K2) { if (K1<0) K1=0; if (K2>N/2-1) K2=N/2-1; if (!x) x=new cdouble[K2-K1+1]; memset(x, 0, sizeof(cdouble)*(K2-K1+1)); for (int l=K1-M; l<=K2+M; l++) { double ang=(f-l)*M_PI; double omg=ang/N; long double si, co, sinn=sin(ang); si=sin(omg), co=cos(omg); double sa=(ang==0)?N:(sinn/si); double saco=sa*co; int k1=l-M, k2=l+M; if (k1<K1) k1=K1; if (k2>K2) k2=K2; for (int k=k1; k<=k2; k++) { int m=k-l, kt=k-K1; if (m<0) m=-m; if (k%2) { x[kt].x-=c[m]*saco; x[kt].y+=c[m]*sinn; } else { x[kt].x+=c[m]*saco; x[kt].y-=c[m]*sinn; } } } return x; }//Window /* function dWindow: calculates the cosine-family-windowed spectrum and its derivative of a complex sinusoid on [0:N-1] at frequency f bins with zero central phase. In: f: frequency, in bins N: window size M, c[]: cosine-family window decomposition coefficients Out: x[0...K2-K1] containing the spectrum at bins K1, ..., K2, dx[0...K2-K1] containing the derivative spectrum at bins K1, ..., K2 No return value. */ void dWindow(cdouble* dx, cdouble* x, double f, int N, int M, double* c, int K1, int K2) { if (K1<0) K1=0; if (K2>N/2-1) K2=N/2-1; memset(x, 0, sizeof(cdouble)*(K2-K1+1)); memset(dx, 0, sizeof(cdouble)*(K2-K1+1)); for (int l=K1-M; l<=K2+M; l++) { double ang=(f-l), Omg=ang*M_PI, omg=Omg/N; long double si, co, sinn=sin(Omg), cosn=cos(Omg); si=sin(omg), co=cos(omg); double sa=(ang==0)?N:(sinn/si), dsa=dsincd_unn(ang, N); double saco=sa*co, dsaco=dsa*co, sinnpi_n=sinn*M_PI/N, cosnpi=cosn*M_PI; int k1=l-M, k2=l+M; if (k1<K1) k1=K1; if (k2>K2) k2=K2; for (int k=k1; k<=k2; k++) { int m=k-l, kt=k-K1; if (m<0) m=-m; if (k%2) { x[kt].x-=c[m]*saco; x[kt].y+=c[m]*sinn; dx[kt].x-=c[m]*(-sinnpi_n+dsaco); dx[kt].y+=c[m]*cosnpi; } else { x[kt].x+=c[m]*saco; x[kt].y-=c[m]*sinn; dx[kt].x+=c[m]*(-sinnpi_n+dsaco); dx[kt].y-=c[m]*cosnpi; } } } }//dWindow /* function ddWindow: calculates the cosine-family-windowed spectrum and its 1st and 2nd derivatives of a complex sinusoid on [0:N-1] at frequency f bins with zero central phase. In: f: frequency, in bins N: window size M, c[]: cosine-family window decomposition coefficients Out: x[0...K2-K1] containing the spectrum at bins K1, ..., K2, dx[0...K2-K1] containing the derivative spectrum at bins K1, ..., K2 ddx[0...K2-K1] containing the 2nd-order derivative spectrum at bins K1, ..., K2 No return value. */ void ddWindow(cdouble* ddx, cdouble* dx, cdouble* x, double f, int N, int M, double* c, int K1, int K2) { if (K1<0) K1=0; if (K2>N/2-1) K2=N/2-1; memset(x, 0, sizeof(cdouble)*(K2-K1+1)); memset(dx, 0, sizeof(cdouble)*(K2-K1+1)); memset(ddx, 0, sizeof(cdouble)*(K2-K1+1)); for (int l=K1-M; l<=K2+M; l++) { double ang=(f-l), Omg=ang*M_PI, omg=Omg/N; long double si, co, sinn=sin(Omg), cosn=cos(Omg); si=sin(omg), co=cos(omg); double sa=(ang==0)?N:(sinn/si), dsa=dsincd_unn(ang, N), ddsa=ddsincd_unn(ang, N); double saco=sa*co, dsaco=dsa*co, sinnpi_n=sinn*M_PI/N, sinnpipi=sinn*M_PI*M_PI, cosnpi=cosn*M_PI, cosnpipi_n=cosnpi*M_PI/N, sipi_n=si*M_PI/N; int k1=l-M, k2=l+M; if (k1<K1) k1=K1; if (k2>K2) k2=K2; for (int k=k1; k<=k2; k++) { int m=k-l, kt=k-K1; if (m<0) m=-m; if (k%2) { x[kt].x-=c[m]*saco; x[kt].y+=c[m]*sinn; dx[kt].x-=c[m]*(-sinnpi_n+dsaco); dx[kt].y+=c[m]*cosnpi; ddx[kt].x-=c[m]*(-cosnpipi_n+ddsa*co-dsa*sipi_n); ddx[kt].y-=c[m]*sinnpipi; } else { x[kt].x+=c[m]*saco; x[kt].y-=c[m]*sinn; dx[kt].x+=c[m]*(-sinnpi_n+dsaco); dx[kt].y-=c[m]*cosnpi; ddx[kt].x+=c[m]*(-cosnpipi_n+ddsa*co-dsa*sipi_n); ddx[kt].y+=c[m]*sinnpipi; } } } }//ddWindow //--------------------------------------------------------------------------- /* function IPWindow: computes the truncated inner product of a windowed spectrum with that of a sinusoid at reference frequency f. In: x[0:N-1]: input spectrum f: reference frequency, in bins M, c[], iH2: cosine-family window specification parameters K1, K2: spectrum truncation bounds, in bins, inclusive returnamplitude: specifies return value, true for amplitude, false for angle Returns the amplitude or phase of the inner product, as specified by $returnamplitude. The return value is interpreted as the actual amplitude/phase of a sinusoid being estimated at f. */ double IPWindow(double f, cdouble* x, int N, int M, double* c, double iH2, int K1, int K2, bool returnamplitude) { cdouble r=IPWindowC(f, x, N, M, c, iH2, K1, K2); double result; if (returnamplitude) result=sqrt(r.x*r.x+r.y*r.y); else result=arg(r); return result; }//IPWindow //wrapper function double IPWindow(double f, void* params) { struct l_ip {int N; int k1; int k2; int M; double* c; double iH2; cdouble* x; double dipwindow; double ipwindow;} *p=(l_ip *)params; return IPWindow(f, p->x, p->N, p->M, p->c, p->iH2, p->k1, p->k2, true); }//IPWindow /* function ddIPWindow: computes the norm of the truncated inner product of a windowed spectrum with that of a sinusoid at reference frequency f, as well as its 1st and 2nd derivatives. In: x[0:N-1]: input spectrum f: reference frequency, in bins M, c[], iH2: cosine-family window specification parameters K1, K2: spectrum truncation bounds, in bins, inclusive Out: ipwindow and dipwindow: the truncated inner product norm and its derivative Returns the 2nd derivative of the norm of the truncated inner product. */ double ddIPWindow(double f, cdouble* x, int N, int M, double* c, double iH2, int K1, int K2, double& dipwindow, double& ipwindow) { if (K1<0) K1=0; if (K2>=N/2) K2=N/2-1; int K=K2-K1+1; cdouble *w=new cdouble[K*3], *dw=&w[K], *ddw=&w[K*2], *lx=&x[K1]; ddWindow(ddw, dw, w, f, N, M, c, K1, K2); cdouble r=Inner(K, lx, w), dr=Inner(K, lx, dw), ddr=Inner(K, lx, ddw); delete[] w; double R2=~r, R=sqrt(R2), dR2=2*(r.x*dr.x+r.y*dr.y), dR=dR2/(2*R), ddR2=2*(r.x*ddr.x+r.y*ddr.y+~dr), ddR=(R*ddR2-dR2*dR)/(2*R2); ipwindow=R*iH2; dipwindow=dR*iH2; return ddR*iH2; }//ddIPWindow //wrapper function double ddIPWindow(double f, void* params) { struct l_ip {int N; int k1; int k2; int M; double* c; double iH2; cdouble* x; double dipwindow; double ipwindow;} *p=(l_ip *)params; return ddIPWindow(f, p->x, p->N, p->M, p->c, p->iH2, p->k1, p->k2, p->dipwindow, p->ipwindow); }//ddIPWindow //--------------------------------------------------------------------------- /* function IPWindowC: computes the truncated inner product of a windowed spectrum with that of a sinusoid at reference frequency f. In: x[0:N-1]: input spectrum f: reference frequency, in bins M, c[], iH2: cosine-family window specification parameters K1, K2: spectrum truncation bounds, in bins, inclusive Returns the inner product. The return value is interpreted as the actual amplitude-phase factor of a sinusoid being estimated at f. */ cdouble IPWindowC(double f, cdouble* x, int N, int M, double* c, double iH2, int K1, int K2) { if (K1<0) K1=0; if (K2>=N/2) K2=N/2-1; int K=K2-K1+1; cdouble *w=new cdouble[K]; cdouble *lx=&x[K1], result=0; Window(w, f, N, M, c, K1, K2); for (int k=0; k<K; k++) result+=lx[k]^w[k]; delete[] w; result*=iH2; return result; }//IPWindowC //--------------------------------------------------------------------------- /* function sIPWindow: computes the total energy of truncated inner products between multiple windowed spectra and that of a sinusoid at a reference frequency f. This does not consider phase alignment between the spectra, supposedly measured at a sequence of known instants. In: x[L][N]: input spectra f: reference frequency, in bins M, c[], iH2: cosine-family window specification parameters K1, K2: spectrum truncation bounds, in bins, inclusive Out: lmd[L]: the actual individual inner products representing actual ampltiude-phase factors (optional) Returns the energy of the vector of inner products. */ double sIPWindow(double f, int L, cdouble** x, int N, int M, double* c, double iH2, int K1, int K2, cdouble* lmd) { double sip=0; if (K1<0) K1=0; if (K2>=N/2) K2=N/2-1; int K=K2-K1+1; cdouble *w=new cdouble[K]; Window(w, f, N, M, c, K1, K2); for (int l=0; l<L; l++) { cdouble *lx=&x[l][K1]; cdouble r=Inner(K, lx, w); if (lmd) lmd[l]=r*iH2; sip+=~r; } sip*=iH2; delete[] w; return sip; }//sIPWindow //wrapper function double sIPWindow(double f, void* params) { struct l_ip {int N; int k1; int k2; int M; double* c; double iH2; int Fr; cdouble** x; double dipwindow; double ipwindow; cdouble* lmd;} *p=(l_ip *)params; return sIPWindow(f, p->Fr, p->x, p->N, p->M, p->c, p->iH2, p->k1, p->k2, p->lmd); }//sIPWindow /* function dsIPWindow: computes the total energy of truncated inner products between multiple windowed spectra and that of a sinusoid at a reference frequency f, as well as its derivative. This does not consider phase synchronization between the spectra, supposedly measured at a sequence of known instants. In: x[L][N]: input spectra f: reference frequency, in bins M, c[], iH2: cosine-family window specification parameters K1, K2: spectrum truncation bounds, in bins, inclusive Out: sip, the energy of the vector of inner products. Returns the derivative of the energy of the vector of inner products. */ double dsIPWindow(double f, int L, cdouble** x, int N, int M, double* c, double iH2, int K1, int K2, double& sip) { if (K1<0) K1=0; if (K2>=N/2) K2=N/2-1; int K=K2-K1+1; cdouble *w=new cdouble[K*2], *dw=&w[K]; dWindow(dw, w, f, N, M, c, K1, K2); double dsip; sip=0; for (int l=0; l<L; l++) { cdouble* lx=&x[l][K1]; cdouble r=Inner(K, lx, w), dr=Inner(K, lx, dw); double R2=~r, dR2=2*(r.x*dr.x+r.y*dr.y); sip+=R2, dsip+=dR2; } sip*=iH2, dsip*=iH2; delete[] w; return dsip; }//dsIPWindow //wrapper function double dsIPWindow(double f, void* params) { struct l_ip1 {int N; int k1; int k2; int M; double* c; double iH2; int Fr; cdouble** x; double sip;} *p=(l_ip1 *)params; return dsIPWindow(f, p->Fr, p->x, p->N, p->M, p->c, p->iH2, p->k1, p->k2, p->sip); }//dsIPWindow /* function dsdIPWindow_unn: computes the energy of unnormalized truncated inner products between a given windowed spectrum and that of a sinusoid at a reference frequency f, as well as its 1st and 2nd derivatives. "Unnormalized" indicates that the inner product cannot be taken as the actual amplitude- phase factor of a sinusoid, but deviate from that by an unspecified factor. In: x[N]: input spectrum f: reference frequency, in bins M, c[], iH2: cosine-family window specification parameters K1, K2: spectrum truncation bounds, in bins, inclusive Out: sipwindow and dsipwindow, the energy and its derivative of the unnormalized inner product. Returns the 2nd derivative of the inner product. */ double ddsIPWindow_unn(double f, cdouble* x, int N, int M, double* c, int K1, int K2, double& dsipwindow, double& sipwindow, cdouble* w_unn) { if (K1<0) K1=0; if (K2>=N/2) K2=N/2-1; int K=K2-K1+1; cdouble *w=new cdouble[K*3], *dw=&w[K], *ddw=&w[K*2]; ddWindow(ddw, dw, w, f, N, M, c, K1, K2); double rr=0, ri=0, drr=0, dri=0, ddrr=0, ddri=0; cdouble *lx=&x[K1]; for (int k=0; k<K; k++) { rr+=lx[k].x*w[k].x+lx[k].y*w[k].y; ri+=lx[k].y*w[k].x-lx[k].x*w[k].y; drr+=lx[k].x*dw[k].x+lx[k].y*dw[k].y; dri+=lx[k].y*dw[k].x-lx[k].x*dw[k].y; ddrr+=lx[k].x*ddw[k].x+lx[k].y*ddw[k].y; ddri+=lx[k].y*ddw[k].x-lx[k].x*ddw[k].y; } delete[] w; double R2=rr*rr+ri*ri, dR2=2*(rr*drr+ri*dri), ddR2=2*(rr*ddrr+ri*ddri+drr*drr+dri*dri); sipwindow=R2; dsipwindow=dR2; if (w_unn) w_unn->x=rr, w_unn->y=ri; return ddR2; }//ddsIPWindow_unn /* function ddsIPWindow: computes the total energy of truncated inner products between multiple windowed spectra and that of a sinusoid at a reference frequency f, as well as its 1st and 2nd derivatives. This does not consider phase synchronization between the spectra, supposedly measured at a sequence of known instants. In: x[L][N]: input spectra f: reference frequency, in bins M, c[], iH2: cosine-family window specification parameters K1, K2: spectrum truncation bounds, in bins, inclusive Out: sip and dsip, the energy of the vector of inner products and its derivative. Returns the 2nd derivative of the energy of the vector of inner products. */ double ddsIPWindow(double f, int L, cdouble** x, int N, int M, double* c, double iH2, int K1, int K2, double& dsip, double& sip) { if (K1<0) K1=0; if (K2>=N/2) K2=N/2-1; int K=K2-K1+1; cdouble *w=new cdouble[K*3], *dw=&w[K], *ddw=&w[K*2]; ddWindow(ddw, dw, w, f, N, M, c, K1, K2); double ddsip=0; dsip=sip=0; for (int l=0; l<L; l++) { cdouble* lx=&x[l][K1]; cdouble r=Inner(K, lx, w), dr=Inner(K, lx, dw), ddr=Inner(K, lx, ddw); double R2=~r, dR2=2*(r.x*dr.x+r.y*dr.y), ddR2=2*(r.x*ddr.x+r.y*ddr.y+~dr); sip+=R2, dsip+=dR2, ddsip+=ddR2; } sip*=iH2, dsip*=iH2, ddsip*=iH2; delete[] w; return ddsip; }//ddsIPWindow //wrapper function double ddsIPWindow(double f, void* params) { struct l_ip1 {int N; int k1; int k2; int M; double* c; double iH2; int Fr; cdouble** x; double dsip; double sip;} *p=(l_ip1 *)params; return ddsIPWindow(f, p->Fr, p->x, p->N, p->M, p->c, p->iH2, p->k1, p->k2, p->dsip, p->sip); }//ddsIPWindow //--------------------------------------------------------------------------- /* function sIPWindowC: computes the total energy of truncated inner products between multiple frames of a spectrogram and multiple frames of a spectrogram of a sinusoid at a reference frequency f. In: x[L][N]: the spectrogram offst_rel: frame offset, relative to frame size f: reference frequency, in bins M, c[], iH2: cosine-family window specification parameters K1, K2: spectrum truncation bounds, in bins, inclusive Out: lmd[L]: the actual individual inner products representing actual ampltiude-phase factors (optional) Returns the energy of the vector of inner products. */ double sIPWindowC(double f, int L, double offst_rel, cdouble** x, int N, int M, double* c, double iH2, int K1, int K2, cdouble* lmd) { if (K1<0) K1=0; if (K2>=N/2) K2=N/2-1; int K=K2-K1+1; cdouble *w=new cdouble[K]; double Cr=0; cdouble Cc=0; Window(w, f, N, M, c, K1, K2); for (int l=0; l<L; l++) { cdouble *lx=&x[l][K1]; cdouble r=Inner(K, lx, w); Cr+=~r; double ph=-4*M_PI*f*offst_rel*l; cdouble r2=r*r; Cc+=r2.rotate(ph); if (lmd) lmd[l]=r; } delete[] w; double result=0.5*iH2*(Cr+abs(Cc)); if (lmd) { double absCc=abs(Cc), hiH2=0.5*iH2; cdouble ej2ph=Cc/absCc; for (int l=0; l<L; l++) { double ph=4*M_PI*f*offst_rel*l; lmd[l]=hiH2*(lmd[l]+(ej2ph**lmd[l]).rotate(ph)); } } return result; }//sIPWindowC //wrapper function double sIPWindowC(double f, void* params) { struct l_ip {int N; int k1; int k2; int M; double* c; double iH2; int L; double offst_rel; cdouble** x; double dipwindow; double ipwindow;} *p=(l_ip *)params; return sIPWindowC(f, p->L, p->offst_rel, p->x, p->N, p->M, p->c, p->iH2, p->k1, p->k2); }//sIPWindowC /* function dsIPWindowC: computes the total energy of truncated inner products between multiple frames of a spectrogram and multiple frames of a spectrogram of a sinusoid at a reference frequency f, together with its derivative. In: x[L][N]: the spectrogram offst_rel: frame offset, relative to frame size f: reference frequency, in bins M, c[], iH2: cosine-family window specification parameters K1, K2: spectrum truncation bounds, in bins, inclusive Out: sip: energy of the vector of the inner products Returns the 1st derivative of the energy of the vector of inner products. */ double dsIPWindowC(double f, int L, double offst_rel, cdouble** x, int N, int M, double* c, double iH2, int K1, int K2, double& sip) { if (K1<0) K1=0; if (K2>=N/2) K2=N/2-1; int K=K2-K1+1; cdouble *w=new cdouble[K*2], *dw=&w[K]; dWindow(dw, w, f, N, M, c, K1, K2); double Cr=0, dCr=0; cdouble Cc=0, dCc=0; for (int l=0; l<L; l++) { cdouble *lx=&x[l][K1]; cdouble r=Inner(K, lx, w), dr=Inner(K, lx, dw); Cr+=~r; dCr+=2*(r.x*dr.x+r.y*dr.y); int two=2; cdouble r2=r*r, dr2=r*dr*two; double lag=-4*M_PI*offst_rel*l, ph=lag*f; Cc=Cc+cdouble(r2).rotate(ph), dCc=dCc+(dr2+cdouble(0,lag)*r2).rotate(ph); } double Cc2=~Cc, dCc2=2*(Cc.x*dCc.x+Cc.y*dCc.y); double Cc1=sqrt(Cc2), dCc1=dCc2/(2*Cc1); sip=0.5*iH2*(Cr+Cc1); double dsip=0.5*iH2*(dCr+dCc1); delete[] w; return dsip; }//dsIPWindowC //wrapper function double dsIPWindowC(double f, void* params) { struct l_ip {int N; int k1; int k2; int M; double* c; double iH2; int L; double offst_rel; cdouble** x; double sip;} *p=(l_ip *)params; return dsIPWindowC(f, p->L, p->offst_rel, p->x, p->N, p->M, p->c, p->iH2, p->k1, p->k2, p->sip); }//dsIPWindowC /* function ddsIPWindowC: computes the total energy of truncated inner products between multiple frames of a spectrogram and multiple frames of a spectrogram of a sinusoid at a reference frequency f, together with its 1st and 2nd derivatives. In: x[L][N]: the spectrogram offst_rel: frame offset, relative to frame size f: reference frequency, in bins M, c[], iH2: cosine-family window specification parameters K1, K2: spectrum truncation bounds, in bins, inclusive Out: sipwindow, dsipwindow: energy of the vector of the inner products and its derivative Returns the 2nd derivative of the energy of the vector of inner products. */ double ddsIPWindowC(double f, int L, double offst_rel, cdouble** x, int N, int M, double* c, double iH2, int K1, int K2, double& dsipwindow, double& sipwindow) { if (K1<0) K1=0; if (K2>=N/2) K2=N/2-1; int K=K2-K1+1; cdouble *w=new cdouble[K*3], *dw=&w[K], *ddw=&w[K*2]; ddWindow(ddw, dw, w, f, N, M, c, K1, K2); double Cr=0, dCr=0, ddCr=0; cdouble Cc=0, dCc=0, ddCc=0; for (int l=0; l<L; l++) { cdouble *lx=&x[l][K1]; cdouble r=Inner(K, lx, w), dr=Inner(K, lx, dw), ddr=Inner(K, lx, ddw); Cr+=~r; dCr+=2*(r.x*dr.x+r.y*dr.y); ddCr+=2*(r.x*ddr.x+r.y*ddr.y+~dr); int two=2; cdouble r2=r*r, dr2=r*dr*two, ddr2=(dr*dr+r*ddr)*two; double lag=-4*M_PI*offst_rel*l, ph=lag*f; Cc=Cc+cdouble(r2).rotate(ph), dCc=dCc+(dr2+cdouble(0,lag)*r2).rotate(ph), ddCc=ddCc+(ddr2+cdouble(0,2*lag)*dr2-r2*lag*lag).rotate(ph); } double Cc2=~Cc, dCc2=2*(Cc.x*dCc.x+Cc.y*dCc.y), ddCc2=2*(Cc.x*ddCc.x+Cc.y*ddCc.y+~dCc); double Cc1=sqrt(Cc2), dCc1=dCc2/(2*Cc1), ddCc1=(Cc1*ddCc2-dCc2*dCc1)/(2*Cc2); sipwindow=0.5*iH2*(Cr+Cc1); dsipwindow=0.5*iH2*(dCr+dCc1); double ddsipwindow=0.5*iH2*(ddCr+ddCc1); delete[] w; return ddsipwindow; }//ddsIPWindowC //wrapper function double ddsIPWindowC(double f, void* params) { struct l_ip {int N; int k1; int k2; int M; double* c; double iH2; int L; double offst_rel; cdouble** x; double dipwindow; double ipwindow;} *p=(l_ip *)params; return ddsIPWindowC(f, p->L, p->offst_rel, p->x, p->N, p->M, p->c, p->iH2, p->k1, p->k2, p->dipwindow, p->ipwindow); }//ddsIPWindowC //-------------------------------------------------------------------------- /* Least-square-error sinusoid detection function version1: picking the highest peak and take measurement of a single sinusoid version2: given a rough peak location and take measurement of a single sinusoid Complex spectrum x is calculated using N data points windowed by a window function that is specified by the parameter set (M, c, iH2). c[0:M] is provided according to Table 3 in the transfer report, on pp.11. iH2 is simply 1/H2, where H2 can be calculated using formula (2.17) on pp.12. f & epf are given/returned in bins. Further reading: "Least-square-error estimation of sinusoids.pdf" */ /* function LSESinusoid: LSE estimation of the predominant stationary sinusoid. In: x[N]: windowed spectrum B: spectral truncation half width, in bins. M, c[], iH2: cosine-family window specification parameters epf: frequency error tolerance, in bins Out: a and pp: amplitude and phase estimates Returns the frequency estimate, in bins. */ double LSESinusoid(cdouble* x, int N, double B, int M, double* c, double iH2, double& a, double& pp, double epf) { struct l_hx {int N; int k1; int k2; int M; double* c; double iH2; cdouble* x; double dhxpeak; double hxpeak;} p={N, 0, 0, M, c, iH2, x, 0, 0}; //(l_hx *)¶ms; int dfshift=int(&((l_hx*)0)->dhxpeak); int inp; double minp=0; for (int i=0; i<N; i++) { double lf=i, tmp; p.k1=ceil(lf-B); if (p.k1<0) p.k1=0; p.k2=floor(lf+B); if (p.k2>=p.N/2) p.k2=p.N/2-1; tmp=IPWindow(lf, &p); if (minp<tmp) inp=i, minp=tmp; } double f=inp; p.k1=ceil(inp-B); if (p.k1<0) p.k1=0; p.k2=floor(inp+B); if (p.k2>=p.N/2) p.k2=p.N/2-1; double tmp=Newton(f, ddIPWindow, &p, dfshift, epf); if (tmp==-1) { Search1Dmax(f, &p, IPWindow, inp-1, inp+1, &a, epf); } else a=p.hxpeak; pp=IPWindow(f, x, N, M, c, iH2, p.k1, p.k2, false); return f; }//LSESinusoid /*function LSESinusoid: LSE estimation of stationary sinusoid near a given initial frequency. In: x[N]: windowed spectrum f: initial frequency, in bins B: spectral truncation half width, in bins. M, c[], iH2: cosine-family window specification parameters epf: frequency error tolerance, in bins Out: f, a and pp: frequency, amplitude and phase estimates No return value. */ void LSESinusoid(double& f, cdouble* x, int N, double B, int M, double* c, double iH2, double& a, double& pp, double epf) { struct l_hx {int N; int k1; int k2; int M; double* c; double iH2; cdouble* x; double dhxpeak; double hxpeak;} p={N, 0, 0, M, c, iH2, x, 0, 0}; int dfshift=int(&((l_hx*)0)->dhxpeak); double inp=f; p.k1=ceil(inp-B); if (p.k1<0) p.k1=0; p.k2=floor(inp+B); if (p.k2>=p.N/2) p.k2=p.N/2-1; double tmp=Newton(f, ddIPWindow, &p, dfshift, epf); if (tmp==-1) { Search1Dmax(f, &p, IPWindow, inp-1, inp+1, &a, epf); } else a=p.hxpeak; pp=IPWindow(f, x, N, M, c, iH2, p.k1, p.k2, false); }//LSESinusoid /* function LSESinusoid: LSE estimation of stationary sinusoid predominant within [f1, f2]. In: x[N]: windowed spectrum [f1, f2]: frequency range B: spectral truncation half width, in bins. M, c[], iH2: cosine-family window specification parameters epf: frequency error tolerance, in bins Out: a and pp: amplitude and phase estimates Returns the frequency estimate, in bins. */ double LSESinusoid(int f1, int f2, cdouble* x, int N, double B, int M, double* c, double iH2, double& a, double& pp, double epf) { struct l_hx {int N; int k1; int k2; int M; double* c; double iH2; cdouble* x; double dhxpeak; double hxpeak;} p={N, 0, 0, M, c, iH2, x, 0, 0}; int dfshift=int(&((l_hx*)0)->dhxpeak); int inp; double minp=0; for (int i=f1; i<f2; i++) { double lf=i, tmp; p.k1=ceil(lf-B); if (p.k1<0) p.k1=0; p.k2=floor(lf+B); if (p.k2>=p.N/2) p.k2=p.N/2-1; tmp=IPWindow(lf, &p); if (minp<tmp) inp=i, minp=tmp; } double f=inp; p.k1=ceil(inp-B); if (p.k1<0) p.k1=0; p.k2=floor(inp+B); if (p.k2>=p.N/2) p.k2=p.N/2-1; double tmp=Newton(f, ddIPWindow, &p, dfshift, epf); if (tmp==-1) { Search1Dmax(f, &p, IPWindow, inp-1, inp+1, &a, epf); } else a=p.hxpeak; pp=IPWindow(f, x, N, M, c, iH2, p.k1, p.k2, false); return f; }//LSESinusoid /* function LSESinusoid: LSE estimation of stationary sinusoid near a given initial frequency within [f1, f2]. In: x[N]: windowed spectrum f: initial frequency, in bins [f1, f2]: frequency range B: spectral truncation half width, in bins. M, c[], iH2: cosine-family window specification parameters epf: frequency error tolerance, in bins Out: f, a and pp: frequency, amplitude and phase estimates Returns 1 if managed to find a sinusoid, 0 if not, upon which $a and $pp are estimated at the initial f. */ int LSESinusoid(double& f, double f1, double f2, cdouble* x, int N, double B, int M, double* c, double iH2, double& a, double& pp, double epf) { struct l_hx {int N; int k1; int k2; int M; double* c; double iH2; cdouble* x; double dhxpeak; double hxpeak;} p={N, 0, 0, M, c, iH2, x, 0, 0};//(l_hx *)¶ms; int dfshift=int(&((l_hx*)0)->dhxpeak); int result=0; double inp=f; p.k1=ceil(inp-B); if (p.k1<0) p.k1=0; p.k2=floor(inp+B); if (p.k2>=p.N/2) p.k2=p.N/2-1; double tmp=Newton(f, ddIPWindow, &p, dfshift, epf, 100, 1e-256, f1, f2); if (tmp!=-1 && f>f1 && f<f2) { result=1; a=p.hxpeak; pp=IPWindow(f, x, N, M, c, iH2, p.k1, p.k2, false); } else { Search1DmaxEx(f, &p, IPWindow, f1, f2, &a, epf); if (f<=f1 || f>=f2) { f=inp; cdouble r=IPWindowC(f, x, N, M, c, iH2, p.k1, p.k2); a=abs(r); pp=arg(r); } else { result=1; pp=IPWindow(f, x, N, M, c, iH2, p.k1, p.k2, false); } } return result; }//LSESinusoid /* function LSESinusoidMP: LSE estimation of a stationary sinusoid from multi-frames spectrogram without considering phase-frequency consistency across frames. In: x[Fr][N]: spectrogram f: initial frequency, in bins [f1, f2]: frequency range B: spectral truncation half width, in bins. M, c[], iH2: cosine-family window specification parameters epf: frequency error tolerance, in bins Out: f, a[Fr] and ph[Fr]: frequency, amplitudes and phase angles estimates Returns an error bound of the frequency estimate. */ double LSESinusoidMP(double& f, double f1, double f2, cdouble** x, int Fr, int N, double B, int M, double* c, double iH2, double* a, double* ph, double epf) { struct l_ip1 {int N; int k1; int k2; int M; double* c; double iH2; int L; cdouble** x; double dsip; double sip; cdouble* lmd;} p={N, 0, 0, M, c,iH2, Fr, x, 0, 0, 0}; int dfshift=int(&((l_ip1*)0)->dsip), fshift=int(&((l_ip1*)0)->sip); double inp=f; p.k1=ceil(inp-B); if (p.k1<0) p.k1=0; p.k2=floor(inp+B); if (p.k2>=p.N/2) p.k2=p.N/2-1; double errf=Newton1dmax(f, f1, f2, ddsIPWindow, &p, dfshift, fshift, dsIPWindow, dfshift, epf); if (errf<0) errf=Search1Dmax(f, &p, sIPWindow, f1, f2, a, epf); if (a || ph) { for (int fr=0; fr<Fr; fr++) { cdouble r=IPWindowC(f, x[fr], N, M, c, iH2, p.k1, p.k2); if (a) a[fr]=abs(r); if (ph) ph[fr]=arg(r); } } return errf; }//LSESinusoidMP /* function LSESinusoidMP: LSE estimation of a stationary sinusoid from multi-frames spectrogram without considering phase-frequency consistency across frames. In: x[Fr][N]: spectrogram f: initial frequency, in bins [f1, f2]: frequency range B: spectral truncation half width, in bins. M, c[], iH2: cosine-family window specification parameters epf: frequency error tolerance, in bins Out: f, a[Fr] and ph[Fr]: frequency, amplitudes and phase angles estimates Returns an error bound of the frequency estimate. Although the frequencies are estimated assuming cross-frame frequency-phase consistency, the final output phase angles are reestimated independently for each frame using the frequency estimate. */ double LSESinusoidMPC(double& f, double f1, double f2, cdouble** x, int Fr, int N, int Offst, double B, int M, double* c, double iH2, double* a, double* ph, double epf) { struct l_ip {int N; int k1; int k2; int M; double* c; double iH2; int L; double offst_rel; cdouble** x; double sdip; double sip;} p={N, 0, 0, M, c,iH2, Fr, Offst*1.0/N, x, 0, 0}; int dfshift=int(&((l_ip*)0)->sdip), fshift=int(&((l_ip*)0)->sip); double inp=f; p.k1=ceil(inp-B); if (p.k1<0) p.k1=0; p.k2=floor(inp+B); if (p.k2>=p.N/2) p.k2=p.N/2-1; double errf=Newton1dmax(f, f1, f2, ddsIPWindowC, &p, dfshift, fshift, dsIPWindowC, dfshift, epf); if (errf<0) errf=Search1Dmax(f, &p, sIPWindowC, f1, f2, a, epf); if (a || ph) { cdouble* lmd=new cdouble[Fr]; sIPWindowC(f, Fr, Offst*1.0/N, x, N, M, c, iH2, p.k1, p.k2, lmd); for (int fr=0; fr<Fr; fr++) { lmd[fr]=IPWindowC(f, x[fr], N, M, c, iH2, p.k1, p.k2); if (a) a[fr]=abs(lmd[fr]); if (ph) ph[fr]=arg(lmd[fr]); } delete[] lmd; } return errf; }//LSESinusoidMPC //--------------------------------------------------------------------------- /* function IPMulti: least square estimation of multiple sinusoids, given their frequencies and an energy suppression index of eps, i.e. the least square error is minimized with an additional eps*||lmd||^2 term. In: x[Wid]: spectrum f[I]: frequencies M, c[]: cosine-family window specification parameters K1, K2: spectral truncation range, i.e. bins outside [K1, K2] are ignored eps: energy suppression factor Out: lmd[I]: amplitude-phase factors No return value. */ void IPMulti(int I, double* f, cdouble* lmd, cdouble* x, int Wid, int K1, int K2, int M, double* c, double eps) { if (K1<0) K1=0; if (K2>=Wid/2) K2=Wid/2-1; int K=K2-K1+1; MList* List=new MList; cdouble** Allocate2L(cdouble, I, K, wt, List); for (int i=0; i<I; i++) Window(wt[i], f[i], Wid, M, c, K1, K2); cdouble** whw=MultiplyXcXt(I, K, wt, List); cdouble* whx=MultiplyXcy(I, K, wt, &x[K1], List); for (int i=0; i<I; i++) whw[i][i]+=eps; GECP(I, lmd, whw, whx); delete List; }//IPMulti /* function IPMulti: least square estimation of multiple sinusoids, given their frequencies and an energy suppression index of eps, and optionally returns residue and sensitivity indicators for each sinusoid. In: x[Wid]: spectrum f[I]: frequencies M, c[]: cosine-family window specification parameters K1, K2: spectral truncation range, i.e. bins outside [K1, K2] are ignored eps: energy suppression factor Out: lmd[I]: amplitude-phase factors sens[I]: sensitivity indicators r1[I]: residue indicators, measured by correlating residue with sinusoid spectra, optional No return value. Sensibitily is computed BEFORE applying eps. */ void IPMulti(int I, double* f, cdouble* lmd, cfloat* x, int Wid, int K1, int K2, int M, double* c, double eps, double* sens, double* r1) { if (K1<0) K1=0; if (K2>=Wid/2) K2=Wid/2-1; int K=K2-K1+1; MList* List=new MList; cdouble** Allocate2L(cdouble, I, K, wt, List); for (int i=0; i<I; i++) Window(wt[i], f[i], Wid, M, c, K1, K2); cdouble** whw=MultiplyXcXt(I, K, wt, List); //*computes sensitivity if required if (sens) { cdouble** iwhw=Copy(I, whw, List); GICP(I, iwhw); cdouble** u=MultiplyXYc(I, I, K, iwhw, wt, List); for (int i=0; i<I; i++) { sens[i]=0; for (int k=0; k<K; k++) sens[i]+=~u[i][k]; sens[i]=sqrt(sens[i]); } } //*/ cdouble* whx=MultiplyXcy(I, K, wt, &x[K1], List); for (int i=0; i<I; i++) whw[i][i]+=eps; GECP(I, lmd, whw, whx); //compute residue if required if (r1) { cdouble* wlmd=MultiplyXty(K, I, wt, lmd, List); //reconstruct for (int k=0; k<K; k++) wlmd[k]=wlmd[k]-x[K1+k]; //-residue for (int i=0; i<I; i++) //r1[i]=Inner(K, wlmd, wt[i]).abs(); //-residue weighted by window { r1[i]=0; for (int k=0; k<K; k++) r1[i]+=abs(wlmd[k])*abs(wt[i][k]); } } delete List; }//IPMulti /* function IPMultiSens: computes the sensitivity of the least square estimation of multiple sinusoids given their frequencies . In: f[I]: frequencies M, c[]: cosine-family window specification parameters K1, K2: spectral truncation range, i.e. bins outside [K1, K2] are ignored eps: energy suppression factor Out: sens[I]: sensitivity indicators No return value. Sensibility is computed AFTER applying eps */ void IPMultiSens(int I, double* f, int Wid, int K1, int K2, int M, double* c, double* sens, double eps) { if (K1<0) K1=0; if (K2>=Wid/2) K2=Wid/2-1; int K=K2-K1+1; MList* List=new MList; cdouble** Allocate2L(cdouble, I, K, wt, List); for (int i=0; i<I; i++) Window(wt[i], f[i], Wid, M, c, K1, K2); cdouble** whw=MultiplyXcXt(I, K, wt, List); for (int i=0; i<I; i++) whw[i][i]+=eps; cdouble** iwhw=Copy(I, whw, List); GICP(I, iwhw); cdouble** u=MultiplyXYc(I, I, K, iwhw, wt, List); for (int i=0; i<I; i++) { sens[i]=0; for (int k=0; k<K; k++) sens[i]+=~u[i][k]; sens[i]=sqrt(sens[i]); } delete List; }//IPMultiSens /* function IPMulti: least square estimation of multi-sinusoids with GIVEN frequencies. This version operates in groups at least B bins from each other, rather than LSE all frequencies together. In: x[Wid]: spectrum f[I]: frequencies, must be ordered low to high. B: number of bins beyond which sinusoids are treated as non-interfering M, c[], iH2: cosine-family window specification parameters Out: lmd[I]: amplitude-phase factors Returns 0. */ double IPMulti(int I, double* f, cdouble* lmd, cdouble* x, int Wid, int M, double* c, double iH2, int B) { int i=0, ist=0; double Bw=B; while (i<I) { if ((i>0 && f[i]-f[i-1]>Bw) || i==I-1) { if (i==I-1) i++; //process frequencies from ist to i-1 if (i-1==ist) //one sinusoid { double fb=f[ist]; int K1=floor(fb-B+0.5), K2=floor(fb+B+0.5); lmd[ist]=IPWindowC(fb, x, Wid, M, c, iH2, K1, K2); } else { MList* List=new MList; int N=i-ist, K1=floor(f[ist]-B+0.5), K2=floor(f[i-1]+B+0.5), K=K2-K1+1; cdouble** Allocate2L(cdouble, N, K, wt, List); for (int n=0; n<N; n++) Window(wt[n], f[ist+n], Wid, M, c, K1, K2); cdouble* whx=MultiplyXcy(N, K, wt, &x[K1], List); //w*'x=(wt*)x cdouble** whw=MultiplyXcXt(N, K, wt, List); /*debug cdouble** C=SubMatrix(0, whw, 1, 4, 1, 4, List); cdouble** C2=SubMatrix(0, whw, 1, 4, 1, 4, List); cdouble** Bh=SubMatrix(0, whw, 1, 4, 0, 1, List); cdouble* Y2=SubVector(0, whx, 1, 4); cdouble x2[4]; cdouble x1=lmd[ist], Bhx1[4], dx2[4]; for (int j=0; j<4; j++) Bhx1[j]=x1^Bh[j][0]; GECP(4, x2, C, Y2); GECP(4, dx2, C2, Bhx1);*/ GECP(N, &lmd[ist], whw, whx); //solving complex linear system (w*'w)a=w*'x delete List; } ist=i; } i++; } return 0; }//IPMulti /* function IPMulti_Direct: LSE estimation of multiple sinusoids given frequencies AND PHASES (direct method) In: x[Wid]: spectrum f[I], ph[I]: frequencies and phase angles. B: spectral truncation half width, in bins; sinusoids over 3B bins apart are regarded non-interfering M, c[], iH2: cosine-family window specification parameters Out: a[I]: amplitudes Returns square norm of the residue. */ double IPMulti_Direct(int I, double* f, double* ph, double* a, cdouble* x, int Wid, int M, double* c, double iH2, int B) { MList* List=new MList; int i=0, ist=0, hWid=Wid/2; cdouble* r=Copy(hWid, x, List); //to store the residue double Bw=3.0*B; while (i<I) { if ((i>0 && f[i]-f[i-1]>Bw) || i==I-1) { if (i==I-1) i++; //process frequencies from ist to i-1 if (i-1==ist) //one sinusoid { double fb=f[ist]; cdouble* w=Window(0, fb, Wid, M, c, 0, hWid-1); for (int k=0; k<hWid; k++) w[k].rotate(ph[ist]); double ip=Inner(2*hWid, (double*)x, (double*)w); a[ist]=ip*iH2; MultiAdd(hWid, r, r, w, -a[ist]); delete[] w; } else { int N=i-ist; cdouble** Allocate2L(cdouble, N, hWid, wt, List); for (int n=0; n<N; n++) { Window(wt[n], f[ist+n], Wid, M, c, 0, hWid-1); for (int k=0; k<hWid; k++) wt[n][k].rotate(ph[ist+n]); } double* whxr=MultiplyXy(N, hWid*2, (double**)wt, (double*)x, List); //w*'x=(wt*)x double** whwr=MultiplyXXt(N, hWid*2, (double**)wt, List); GECP(N, &a[ist], whwr, whxr); //solving complex linear system (w*'w)a=w*'x for (int n=0; n<N; n++) MultiAdd(hWid, r, r, wt[n], -a[ist+n]); } ist=i; } i++; } double result=Inner(hWid, r, r).x; delete List; return result; }//IPMulti_Direct /* function IPMulti_GS: LSE estimation of multiple sinusoids given frequencies AND PHASES (Gram-Schmidt method) In: x[Wid]: spectrum f[I], ph[I]: frequencies and phase angles. B: spectral truncation, in bins; sinusoids over 3B bins apart are regarded non-interfering M, c[], iH2: cosine-family window specification parameters Out: a[I]: amplitudes Returns square norm of the residue. */ double IPMulti_GS(int I, double* f, double* ph, double* a, cdouble* x, int Wid, int M, double* c, double iH2, int B, double** L, double** Q) { MList* List=new MList; int i=0, ist=0, hWid=Wid/2; cdouble* r=Copy(hWid, x, List); //to store the residue double Bw=3.0*B; while (i<I) { if ((i>0 && f[i]-f[i-1]>Bw) || i==I-1) { if (i==I-1) i++; //process frequencies from ist to i-1 if (i-1==ist) //one sinusoid { double fb=f[ist]; cdouble* w=Window(0, fb, Wid, M, c, 0, hWid-1); for (int k=0; k<hWid; k++) w[k].rotate(ph[ist]); double ip=Inner(2*hWid, (double*)x, (double*)w); a[ist]=ip*iH2; MultiAdd(hWid, r, r, w, -a[ist]); delete[] w; } else { int N=i-ist; cdouble** Allocate2L(cdouble, N, hWid, wt, List); Alloc2L(N, N, L, List); Alloc2L(N, hWid*2, Q, List); for (int n=0; n<N; n++) { Window(wt[n], f[ist+n], Wid, M, c, 0, hWid-1); for (int k=0; k<hWid; k++) wt[n][k].rotate(ph[ist+n]); } LQ_GS(N, hWid*2, (double**)wt, L, Q); double* atl=MultiplyxYt(N, hWid*2, (double*)x, Q, List); GExL(N, &a[ist], L, atl); for (int n=0; n<N; n++) MultiAdd(hWid, r, r, wt[n], -a[ist+n]); } ist=i; } i++; } double result=Inner(hWid, r, r).x; delete List; return result; }//IPMulti_GS /* function IPMulti: LSE estimation of I sinusoids given frequency and phase and J sinusoids given frequency only In: x[Wid]: spectrum f[I+J], ph[I]: frequencies and phase angles M, c[], iH2: cosine-family window specification parameters Out: a[I+J]: amplitudes ph[I:I+J-1]: phase angles not given on start wt[I+2J][hWid], Q[I+2J][hWid], L[I+2J][I+2J]: internal w matrix and its LQ factorization, optional Returns the residue vector, newly created and registered to RetList, if specified. On start a[] should have valid storage no less than I+2J. */ cdouble* IPMulti(int I, int J, double* f, double* ph, double* a, cdouble* x, int Wid, int M, double* c, cdouble** wt, cdouble** Q, double** L, MList* RetList) { MList* List=new MList; int hWid=Wid/2; cdouble* r=Copy(hWid, x, RetList); //to store the residue if (!wt){Allocate2L(cdouble, I+J*2, hWid, wt, List);} if (!Q){Allocate2L(cdouble, I+J*2, hWid, Q, List);} if (!L){Allocate2L(double, I+J*2, I+J*2, L, List);} memset(wt[0], 0, sizeof(cdouble)*(I+J*2)*hWid); memset(Q[0], 0, sizeof(cdouble)*(I+J*2)*hWid); memset(L[0], 0, sizeof(double)*(I+J*2)*(I+J*2)); //*The direct form for (int i=0; i<I; i++) { Window(wt[i], f[i], Wid, M, c, 0, hWid-1); for (int k=0; k<hWid; k++) wt[i][k].rotate(ph[i]); } for (int j=0; j<J; j++) { cdouble *w1=wt[I+j*2], *w2=wt[I+j*2+1]; Window(w1, f[I+j], Wid, M, c, 0, hWid-1); for (int k=0; k<hWid; k++) w2[k].y=w1[k].x, w2[k].x=-w1[k].y; } LQ_GS(I+J*2, hWid*2, (double**)wt, L, (double**)Q); double *atl=MultiplyxYt(I+J*2, hWid*2, (double*)x, (double**)Q, List); GExL(I+J*2, a, L, atl); for (int i=0; i<I+J*2; i++) MultiAdd(hWid, r, r, wt[i], -a[i]); for (int j=0; j<J; j++) { double xx=a[I+j*2], yy=a[I+j*2+1]; a[I+j]=sqrt(xx*xx+yy*yy); ph[I+j]=atan2(yy, xx); } delete List; return r; }//IPMulti //--------------------------------------------------------------------------- /* Routines for estimation two sinusoids with 1 fixed and 1 flexible frequency Further reading: "LSE estimation for 2 sinusoids with 1 at a fixed frequency.pdf" */ /* function WindowDuo: calcualtes the square norm of the inner product between windowed spectra of two sinusoids at frequencies f1 and f2, df=f1-f2. In: df: frequency difference, in bins N: DFT size M, d[]: cosine-family window specification parameters (see "further reading"). Out: w[0], the inner product, optional Returns square norm of the inner product. */ double WindowDuo(double df, int N, double* d, int M, cdouble* w) { double wr=0, wi=0; for (int m=-2*M; m<=2*M; m++) { double ang=df+m, Omg=ang*M_PI, omg=Omg/N; double si=sin(omg), co=cos(omg), sinn=sin(Omg); double sa=(ang==0)?N:(sinn/si); double dm; if (m<0) dm=d[-m]; else dm=d[m]; wr+=dm*sa*co, wi+=-dm*sinn; } wr*=N, wi*=N; if (w) w->x=wr, w->y=wi; double result=wr*wr+wi*wi; return result; }//WindowDuo /* function ddWindowDuo: calcualtes the square norm of the inner product between windowed spectra of two sinusoids at frequencies f1 and f2, df=f1-f2, with its 1st and 2nd derivatives In: df: frequency difference, in bins N: DFT size M, d[]: cosine-family window specification parameters (see "further reading" for d[]). Out: w[0], the inner product, optional window, dwindow: square norm and its derivative, of the inner product Returns 2nd derivative of the square norm of the inner product. */ double ddWindowDuo(double df, int N, double* d, int M, double& dwindow, double& window, cdouble* w) { double wr=0, wi=0, dwr=0, dwi=0, ddwr=0, ddwi=0, PI_N=M_PI/N, PIPI_N=PI_N*M_PI, PIPI=M_PI*M_PI; for (int m=-2*M; m<=2*M; m++) { double ang=df+m, Omg=ang*M_PI, omg=Omg/N; double si=sin(omg), co=cos(omg), sinn=sin(Omg), cosn=cos(Omg); double sa=(ang==0)?N:(sinn/si), dsa=dsincd_unn(ang, N), ddsa=ddsincd_unn(ang, N); double dm; if (m<0) dm=d[-m]; else dm=d[m]; wr+=dm*sa*co, wi+=-dm*sinn; dwr+=dm*(dsa*co-PI_N*sinn), dwi+=-dm*M_PI*cosn; ddwr+=dm*(ddsa*co-PI_N*dsa*si-PIPI_N*cosn), ddwi+=dm*PIPI*sinn; } wr*=N, wi*=N, dwr*=N, dwi*=N, ddwr*=N, ddwi*=N; window=wr*wr+wi*wi; dwindow=2*(wr*dwr+wi*dwi); if (w) w->x=wr, w->y=wi; double ddwindow=2*(wr*ddwr+dwr*dwr+wi*ddwi+dwi*dwi); return ddwindow; }//ddWindowDuo /* function sIPWindowDuo: calculates the square norm of the orthogonal projection of a windowed spectrum onto the linear span of the windowed spectra of two sinusoids at reference frequencies f1 and f2. In: x[N]: spectrum f1, f2: reference frequencies. M, c[], d[], iH2: cosine-family window specification parameters. K1, K2: spectrum truncation range, i.e. bins outside [K1, K2] are ignored. Out: lmd1, lmd2: projection coefficients, interpreted as actual amplitude-phase factors Returns the square norm of the orthogonal projection. */ double sIPWindowDuo(double f1, double f2, cdouble* x, int N, double* c, double* d, int M, double iH2, int K1, int K2, cdouble& lmd1, cdouble& lmd2) { int K=K2-K1+1; cdouble xw1=0, *lx=&x[K1], *w1=new cdouble[K*2], *r1=&w1[K]; Window(w1, f1, N, M, c, K1, K2); double w1w1=0; for (int k=0; k<K; k++) xw1+=(lx[k]^w1[k]), w1w1+=~w1[k]; cdouble mu1=xw1/w1w1; for (int k=0; k<K; k++) r1[k]=lx[k]-mu1*w1[k]; Window(w1, f2, N, M, c, K1, K2); cdouble r1w2=0, w12; for (int k=0; k<K; k++) r1w2+=(r1[k]^w1[k]); double w=WindowDuo(f1-f2, N, d, M, &w12); double v=1.0/iH2-w*iH2; double result=~xw1/w1w1+~r1w2/v; cdouble mu2=r1w2/v; lmd2=mu2; lmd1=mu1-(mu2^w12)*iH2; delete[] w1; return result; }//sIPWindowDuo //wrapper function double sIPWindowDuo(double f2, void* params) { struct l_ip {int N; int k1; int k2; double* c; double* d; int M; double iH2; cdouble* x; double f1; double dipwindow; double ipwindow;} *p=(l_ip *)params; cdouble r1, r2; return sIPWindowDuo(p->f1, f2, p->x, p->N, p->c, p->d, p->M, p->iH2, p->k1, p->k2, r1, r2); }//sIPWindowDuo /* function ddsIPWindowDuo: calculates the square norm, and its 1st and 2nd derivatives against f2,, of the orthogonal projection of a windowed spectrum onto the linear span of the windowed spectra of two sinusoids at reference frequencies f1 and f2. In: x[N]: spectrum f1, f2: reference frequencies. M, c[], d[], iH2: cosine-family window specification parameters. K1, K2: spectrum truncation range, i.e. bins outside [K1, K2] are ignored. Out: lmd1, lmd2: projection coefficients, interpreted as actual amplitude-phase factors ddsip[3]: the 2nd, 1st and 0th derivatives (against f2) of the square norm. No return value. */ void ddsIPWindowDuo(double* ddsip2, double f1, double f2, cdouble* x, int N, double* c, double* d, int M, double iH2, int K1, int K2, cdouble& lmd1, cdouble& lmd2) { int K=K2-K1+1; cdouble xw1=0, *lx=&x[K1], *w1=new cdouble[K*2], *r1=&w1[K]; Window(w1, f1, N, M, c, K1, K2); double w1w1=0; for (int k=0; k<K; k++) xw1+=(lx[k]^w1[k]), w1w1+=~w1[k]; cdouble mu1=xw1/w1w1; for (int k=0; k<K; k++) r1[k]=lx[k]-mu1*w1[k]; cdouble r1w2, w12; double u, du, ddu=ddsIPWindow_unn(f2, &r1[-K1], N, M, c, K1, K2, du, u, &r1w2); double w, dw, ddw=ddWindowDuo(f1-f2, N, d, M, dw, w, &w12); dw=-dw; double v=1.0/iH2-w*iH2, dv=-iH2*dw, ddv=-iH2*ddw; double iv=1.0/v;//, div=-dv*iv*iv, ddiv=(2*dv*dv-v*ddv)*iv*iv*iv; ddsip2[2]=~xw1/w1w1+u*iv; ddsip2[1]=iv*(du-iv*u*dv); ddsip2[0]=iv*(ddu-iv*(u*ddv+2*du*dv-2*iv*u*dv*dv)); cdouble mu2=r1w2*iv; lmd2=mu2; lmd1=mu1-(mu2^w12)*iH2; delete[] w1; }//ddsIPWindowDuo //wrapper function double ddsIPWindowDuo(double f2, void* params) { struct l_ip {int N; int k1; int k2; double* c; double* d; int M; double iH2; cdouble* x; double f1; double dipwindow; double ipwindow;} *p=(l_ip *)params; double ddsip2[3]; cdouble r1, r2; ddsIPWindowDuo(ddsip2, p->f1, f2, p->x, p->N, p->c, p->d, p->M, p->iH2, p->k1, p->k2, r1, r2); p->dipwindow=ddsip2[1], p->ipwindow=ddsip2[2]; return ddsip2[0]; }//ddsIPWindowDuo /* function LSEDuo: least-square estimation of two sinusoids of which one has a fixed frequency In: x[N]: the windowed spectrum f1: the fixed frequency f2: initial value of the flexible frequency fmin, fmax: search range for f2, the flexible frequency B: spectral truncation half width M, c[], d[], iH2: epf: frequency error tolerance Out: f2: frequency estimate lmd1, lmd2: amplitude-phase factor estimates Returns 1 if managed to find a good f2, 0 if not, upon which the initial f2 is used for estimating amplitudes and phase angles. */ int LSEDuo(double& f2, double fmin, double fmax, double f1, cdouble* x, int N, double B, double* c, double* d, int M, double iH2, cdouble& r1, cdouble &r2, double epf) { int result=0; double inp=f2; int k1=ceil(inp-B); if (k1<0) k1=0; int k2=floor(inp+B); if (k2>=N/2) k2=N/2-1; struct l_hx {int N; int k1; int k2; double* c; double* d; int M; double iH2; cdouble* x; double f1; double dipwindow; double ipwindow;} p={N, k1, k2, c, d, M, iH2, x, f1, 0, 0}; int dfshift=int(&((l_hx*)0)->dipwindow);// fshift=int(&((l_hx*)0)->ipwindow); double tmp=Newton(f2, ddsIPWindowDuo, &p, dfshift, epf, 100, 1e-256, fmin, fmax); if (tmp!=-1 && f2>fmin && f2<fmax) result=1; else { Search1DmaxEx(f2, &p, sIPWindowDuo, fmin, fmax, NULL, epf); if (f2<=fmin || f2>=fmax) f2=inp; else result=1; } sIPWindowDuo(f1, f2, x, N, c, d, M, iH2, k1, k2, r1, r2); return result; }//LSEDuo //--------------------------------------------------------------------------- /* Time-frequency reassignment sinusoid estimation routines. Further reading: A. R?bel, ¡°Estimating partial frequency and frequency slope using reassignment operators,¡± in Proc. ICMC¡¯02. G?teborg. 2002. */ /* function CDFTW: single-frequency windowed DTFT, centre-aligned In: data[Wid]: waveform data x win[Wid+1]: window function k: frequency, in bins, where bin=1/Wid Out: X: DTFT of xw at frequency k bins No return value. */ void CDFTW(cdouble& X, double k, int Wid, cdouble* data, double* win) { X=0; int hWid=Wid/2; for (int i=0; i<Wid; i++) { cdouble tmp=data[i]*win[Wid-i]; double ph=-2*M_PI*(i-hWid)*k/Wid; tmp.rotate(ph); X+=tmp; } }//CDFTW /* function CuDFTW: single-frequency windowed DTFT of t*data[t], centre-aligned In: data[Wid]: waveform data x wid[Wid+1]: window function k: frequency, in bins Out: X: DTFT of txw at frequency k bins No return value. */ void CuDFTW(cdouble& X, int k, int Wid, cdouble* data, double* win) { X=0; int hWid=Wid/2; for (int i=0; i<Wid; i++) { double tw=((i-hWid)*win[Wid-i]); cdouble tmp=data[i]*tw; double ph=-2*M_PI*(i-hWid)*k/Wid; tmp.rotate(ph); X+=tmp; } }//CuDFTW /* function TFReas: time-frequency reassignment In: data[Wid]: waveform data win[Wid+1], dwin[Wid+1], ddwin[Wid+1]: window function and its derivatives f, t: initial digital frequency and time Out: f, t: reassigned digital frequency and time fslope: estimate of frequency derivative plogaslope[0]: estimate of the derivative of logarithmic amplitude, optional No return value. */ void TFReas(double& f, double& t, double& fslope, int Wid, cdouble* data, double* win, double* dwin, double* ddwin, double* plogaslope) { int fi=floor(f*Wid+0.5); cdouble x, xt, xw; CDFTW(x, fi, Wid, data, win); CuDFTW(xw, fi, Wid, data, win); xt.x=xw.y; xw.y=-xw.x; xw.x=xt.x; CDFTW(xt, fi, Wid, data, dwin); double px=~x; t=t-(xw.y*x.x-xw.x*x.y)/px; f=1.0*fi/Wid+(xt.y*x.x-xt.x*x.y)/px/(2*M_PI); if (plogaslope) plogaslope[0]=-(xt.x*x.x+xt.y*x.y)/px; cdouble xtt, xtw; CuDFTW(xtw, fi, Wid, data, dwin); xtt.x=xtw.y; xtw.y=-xtw.x; xtw.x=xtt.x; CDFTW(xtt, fi, Wid, data, ddwin); double dtdt=-(xtw.y*x.x-xtw.x*x.y)/px+((xt.y*x.x-xt.x*x.y)*(xw.x*x.x+xw.y*x.y)+(xt.x*x.x+xt.y*x.y)*(xw.y*x.x-xw.x*x.y))/px/px, dwdt=(xtt.y*x.x-xtt.x*x.y)/px-2*(xt.x*x.x+xt.y*x.y)*(xt.y*x.x-xt.x*x.y)/px/px; if (dtdt!=0) fslope=dwdt/dtdt/(2*M_PI); else fslope=0; } //TFReas*/ /* function TFReas: sinusoid estimation using reassignment method In: data[Wid]: waveform data w[Wid+1], dw[Wid+1], ddw[Wid+1]: window function and its derivatives win[Wid]: window function used for estimating amplitude and phase by projection onto a chirp t: time for which the parameters are estimated f: initial frequency at t Out: f, a, ph: digital frequency, amplitude and phase angle estimated at t fslope: frequency derivative estimate No return value. */ void TFReas(double& f, double t, double& a, double& ph, double& fslope, int Wid, cdouble* data, double* w, double* dw, double* ddw, double* win) { double localt=t, logaslope; TFReas(f, localt, fslope, Wid, data, w, dw, ddw, &logaslope); if (logaslope*Wid>6) logaslope=6.0/Wid; else if (logaslope*Wid<-6) logaslope=-6.0/Wid; f=f+fslope*(t-localt); //obtain frequency estimate at t cdouble x=0; if (win==0) { for (int n=0; n<Wid; n++) { double ni=n-t; cdouble tmp=data[n]; double p=-2*M_PI*(f+0.5*fslope*ni)*ni; tmp.rotate(p); x+=tmp; } a=abs(x)/Wid; } else { double sumwin=0; for (int n=0; n<Wid; n++) { double ni=n-t; cdouble tmp=data[n]*win[n]; double p=-2*M_PI*(f+0.5*fslope*ni)*ni; tmp.rotate(p); x+=tmp; sumwin+=win[n]; } a=abs(x)/sumwin; } ph=arg(x); }//TFReas //--------------------------------------------------------------------------- /* Routines for additive and multiplicative reestimation of sinusoids. Further reading: Wen X. and M. Sandler, "Additive and multiplicative reestimation schemes for the sinusoid modeling of audio," in Proc. EUSIPCO'09, Glasgow, 2009. */ /* function AdditiveUpdate: additive reestimation of time-varying sinusoid In: x[Count]: waveform data Wid, Offst: frame size and hop fs[Count], as[Count], phs[Count]: initial estimate of sinusoid parameters das[Count]: initial estimate of amplitude derivative BasicAnalyzer: pointer to a sinusoid analyzer LogA: indicates if amplitudes are interpolated at cubic spline or exponential cubic spline Out: fs[Count], as[Count], phs[Count], das[Count]: estimates after additive update No return value. */ void AdditiveUpdate(double* fs, double* as, double* phs, double* das, cdouble* x, int Count, int Wid, int Offst, TBasicAnalyzer BasicAnalyzer, int reserved, bool LogA) { int HWid=Wid/2, Fr=(Count-Wid)/Offst+1; for (int fr=0; fr<Fr; fr++) { int i=HWid+Offst*fr; if (fs[i]<0 || fs[i]>0.5){} } cdouble *y=new cdouble[Count]; double *lf=new double[Count*4], *la=&lf[Count], *lp=&lf[Count*2], *lda=&lf[Count*3]; __int16* ref=new __int16[Count]; for (int i=0; i<Count; i++) y[i]=x[i].x-as[i]*cos(phs[i]), ref[i]=floor(fs[i]*Wid+0.5); memcpy(lf, fs, sizeof(double)*Count); BasicAnalyzer(lf, la, lp, lda, y, Count, Wid, Offst, ref, reserved, LogA); //merge and interpolate double *fa=new double[Fr*12], *fb=&fa[Fr], *fc=&fa[Fr*2], *fd=&fa[Fr*3], *aa=&fa[Fr*4], *ab=&aa[Fr], *ac=&aa[Fr*2], *ad=&aa[Fr*3], *xs=&fa[Fr*8], *ffr=&xs[Fr], *afr=&xs[Fr*2], *pfr=&xs[Fr*3]; for (int fr=0; fr<Fr; fr++) { int i=HWid+Offst*fr; double a=as[i], b=la[i], fai=phs[i], thet=lp[i], f=fs[i], g=lf[i], delt=fai-thet, da=das[i], db=lda[i]; xs[fr]=i; if (fabs(f-g)*Wid>1) { afr[fr]=a, pfr[fr]=fai, ffr[fr]=f; } else { double rr=a*cos(fai)+b*cos(thet); double ii=a*sin(fai)+b*sin(thet); ffr[fr]=(a*f*(a+b*cos(delt))+b*g*(b+a*cos(delt))+(da*b-a*db)*sin(delt)/(2*M_PI))/(a*a+b*b+2*a*b*cos(delt)); afr[fr]=sqrt(rr*rr+ii*ii); pfr[fr]=atan2(ii, rr); } if (LogA) afr[fr]=log(afr[fr]); } CubicSpline(Fr-1, fa, fb, fc, fd, xs, ffr, 1, 1); CubicSpline(Fr-1, aa, ab, ac, ad, xs, afr, 1, 1); for (int fr=0; fr<Fr-1; fr++) Sinusoid(&fs[int(xs[fr])], &as[int(xs[fr])], &phs[int(xs[fr])], &das[int(xs[fr])], 0, Offst, aa[fr], ab[fr], ac[fr], ad[fr], fa[fr], fb[fr], fc[fr], fd[fr], pfr[fr], pfr[fr+1], LogA); Sinusoid(&fs[int(xs[0])], &as[int(xs[0])], &phs[int(xs[0])], &das[int(xs[0])], -HWid, 0, aa[0], ab[0], ac[0], ad[0], fa[0], fb[0], fc[0], fd[0], pfr[0], pfr[1], LogA); Sinusoid(&fs[int(xs[Fr-2])], &as[int(xs[Fr-2])], &phs[int(xs[Fr-2])], &das[int(xs[Fr-2])], Offst, Offst+HWid, aa[Fr-2], ab[Fr-2], ac[Fr-2], ad[Fr-2], fa[Fr-2], fb[Fr-2], fc[Fr-2], fd[Fr-2], pfr[Fr-2], pfr[Fr-1], LogA); delete[] fa; //*/ /* for (int i=0; i<Count; i++) { double rr=as[i]*cos(phs[i])+la[i]*cos(lp[i]); double ii=as[i]*sin(phs[i])+la[i]*sin(lp[i]); as[i]=sqrt(rr*rr+ii*ii); phs[i]=atan2(ii, rr); } //*/ for (int fr=0; fr<Fr; fr++) { int i=HWid+Offst*fr; if (fs[i]<0 || fs[i]>0.5){} } delete[] y; delete[] lf; delete[] ref; }//AdditiveUpdate /* function AdditiveAnalyzer: sinusoid analyzer with one additive update In: x[Count]: waveform data Wid, Offst: frame size and hop size BasicAnalyzer: pointer to a sinusoid analyzer ref[Count]: reference frequencies, in bins, used by BasicAnalyzer BasicAnalyzer: pointer to a sinusoid analyzer LogA: indicates if amplitudes are interpolated at cubic spline or exponential cubic spline Out: fs[Count], as[Count], phs[Count]: sinusoid parameter estimates das[Count]: estimate of amplitude derivative No return value. */ void AdditiveAnalyzer(double* fs, double* as, double* phs, double* das, cdouble* x, int Count, int Wid, int Offst, __int16* ref, TBasicAnalyzer BasicAnalyzer, int reserved, bool LogA) { BasicAnalyzer(fs, as, phs, das, x, Count, Wid, Offst, ref, reserved, LogA); AdditiveUpdate(fs, as, phs, das, x, Count, Wid, Offst, BasicAnalyzer, reserved, LogA); }//AdditiveAnalyzer /* function MultiplicativeUpdate: multiplicative reestimation of time-varying sinusoid In: x[Count]: waveform data Wid, Offst: frame size and hop fs[Count], as[Count], phs[Count]: initial estimate of sinusoid parameters das[Count]: initial estimate of amplitude derivative BasicAnalyzer: pointer to a sinusoid analyzer LogA: indicates if amplitudes are interpolated at cubic spline or exponential cubic spline Out: fs[Count], as[Count], phs[Count], das[Count]: estimates after additive update No return value. */ void MultiplicativeUpdate(double* fs, double* as, double* phs, double* das, cdouble* x, int Count, int Wid, int Offst, TBasicAnalyzer BasicAnalyzer, int reserved, bool LogA) { int HWid=Wid/2; cdouble *y=new cdouble[Count]; double *lf=new double[Count*8], *la=&lf[Count], *lp=&lf[Count*2], *lda=&lf[Count*3], *lf2=&lf[Count*4], *la2=&lf2[Count], *lp2=&lf2[Count*2], *lda2=&lf2[Count*3]; __int16 *lref=new __int16[Count]; for (int i=0; i<Count; i++) y[i]=x[i]*(cdouble(1.0).rotate(-phs[i]+i*0.15*2*M_PI)), lref[i]=0.15*Wid; BasicAnalyzer(lf, la, lp, lda, y, Count, Wid, Offst, lref, reserved, LogA); for (int i=0; i<Count; i++) y[i]=y[i]*(cdouble(1.0/la[i]).rotate(-lp[i]+i*0.15*2*M_PI)), lref[i]=0.15*Wid; BasicAnalyzer(lf2, la2, lp2, lda2, y, Count, Wid, Offst, lref, reserved, LogA); /* for (int i=0; i<Count; i++) { as[i]=la[i]*la2[i]; phs[i]=phs[i]+lp[i]+lp2[i]-0.3*2*M_PI*i; fs[i]=fs[i]+lf[i]+lf2[i]-0.3; } //*/ //merge int Fr=(Count-Wid)/Offst+1; double *fa=new double[Fr*12], *fb=&fa[Fr], *fc=&fa[Fr*2], *fd=&fa[Fr*3], *aa=&fa[Fr*4], *ab=&aa[Fr], *ac=&aa[Fr*2], *ad=&aa[Fr*3], *xs=&fa[Fr*8], *ffr=&xs[Fr], *afr=&xs[Fr*2], *pfr=&xs[Fr*3]; for (int fr=0; fr<Fr; fr++) { int i=HWid+Offst*fr; xs[fr]=i; afr[fr]=la[i]*la2[i]; if (LogA) afr[fr]=log(afr[fr]); ffr[fr]=fs[i]+lf[i]-0.15+lf2[i]-0.15; pfr[fr]=phs[i]+lp[i]+lp2[i]-0.3*i*2*M_PI; } CubicSpline(Fr-1, fa, fb, fc, fd, xs, ffr, 1, 1); CubicSpline(Fr-1, aa, ab, ac, ad, xs, afr, 1, 1); for (int fr=0; fr<Fr-1; fr++) Sinusoid(&fs[int(xs[fr])], &as[int(xs[fr])], &phs[int(xs[fr])], &das[int(xs[fr])], 0, Offst, aa[fr], ab[fr], ac[fr], ad[fr], fa[fr], fb[fr], fc[fr], fd[fr], pfr[fr], pfr[fr+1], LogA); Sinusoid(&fs[int(xs[0])], &as[int(xs[0])], &phs[int(xs[0])], &das[int(xs[0])], -HWid, 0, aa[0], ab[0], ac[0], ad[0], fa[0], fb[0], fc[0], fd[0], pfr[0], pfr[1], LogA); Sinusoid(&fs[int(xs[Fr-2])], &as[int(xs[Fr-2])], &phs[int(xs[Fr-2])], &das[int(xs[Fr-2])], Offst, Offst+HWid, aa[Fr-2], ab[Fr-2], ac[Fr-2], ad[Fr-2], fa[Fr-2], fb[Fr-2], fc[Fr-2], fd[Fr-2], pfr[Fr-2], pfr[Fr-1], LogA); delete[] fa; //*/ for (int fr=0; fr<Fr; fr++) { int i=HWid+Offst*fr; if (fs[i]<0 || fs[i]>0.5){} } delete[] y; delete[] lf; delete[] lref; }//MultiplicativeUpdate /* function MultiplicativeAnalyzer: sinusoid analyzer with one multiplicative update In: x[Count]: waveform data Wid, Offst: frame size and hop size BasicAnalyzer: pointer to a sinusoid analyzer ref[Count]: reference frequencies, in bins, used by BasicAnalyzer BasicAnalyzer: pointer to a sinusoid analyzer LogA: indicates if amplitudes are interpolated at cubic spline or exponential cubic spline Out: fs[Count], as[Count], phs[Count]: sinusoid parameter estimates das[Count]: estimate of amplitude derivative No return value. */ void MultiplicativeAnalyzer(double* fs, double* as, double* phs, double* das, cdouble* x, int Count, int Wid, int Offst, __int16* ref, TBasicAnalyzer BasicAnalyzer, int reserved, bool LogA) { BasicAnalyzer(fs, as, phs, das, x, Count, Wid, Offst, ref, reserved, LogA); MultiplicativeUpdate(fs, as, phs, das, x, Count, Wid, Offst, BasicAnalyzer, reserved); }//MultiplicativeAnalyzer /* This is an earlier version of the multiplicative method without using a user-provided BasicAnalyzer. This updates the sinusoid estimates at the selected consecutive FRAMES of x. Only frequency modulation is included in the multiplier. The first frame (0) is centred at x[Wid/2]. fs, as, and phs are based on frames rather than samples. Updates include frame frst, but not frame fren. */ void MultiplicativeUpdateF(double* fs, double* as, double* phs, __int16* x, int Fr, int frst, int fren, int Wid, int Offst) { int HWid=Wid/2; double *fa=new double[Fr*12], *fb=&fa[Fr], *fc=&fa[Fr*2], *fd=&fa[Fr*3], *xs=&fa[Fr*8]; for (int fr=0; fr<Fr; fr++) xs[fr]=HWid+Offst*fr; CubicSpline(Fr-1, fa, fb, fc, fd, xs, fs, 1, 1); int dst=Offst*frst, den=Offst*(fren-1)+Wid, dcount=den-dst; double *f=new double[dcount*2], *ph=&f[dcount]; for (int fr=frst; fr<fren-1; fr++) Sinusoid(&f[int(xs[fr])-dst], &ph[int(xs[fr])-dst], 0, Offst, fa[fr], fb[fr], fc[fr], fd[fr], phs[fr], phs[fr+1]); if (frst==0) Sinusoid(&f[int(xs[0])-dst], &ph[int(xs[0])-dst], -HWid, 0, fa[0], fb[0], fc[0], fd[0], phs[0], phs[1]); else Sinusoid(&f[int(xs[frst-1])-dst], &ph[int(xs[frst-1])-dst], 0, Offst, fa[frst-1], fb[frst-1], fc[frst-1], fd[frst-1], phs[frst-1], phs[frst]); if (fren==Fr) Sinusoid(&f[int(xs[fren-2])-dst], &ph[int(xs[fren-2])-dst], Offst, Offst+HWid, fa[fren-2], fb[fren-2], fc[fren-2], fd[fren-2], phs[fren-2], phs[fren-1]); else Sinusoid(&f[int(xs[fren-1])-dst], &ph[int(xs[fren-1])-dst], 0, Offst, fa[fren-1], fb[fren-1], fc[fren-1], fd[fren-1], phs[fren-1], phs[fren]); cdouble* y=new cdouble[Wid]; AllocateFFTBuffer(Wid, Amp, W, X); double* win=NewWindow(wtHann, Wid); int M; double c[10], iH2; windowspec(wtHann, Wid, &M, c, &iH2); for (int fr=frst; fr<fren; fr++) { __int16* lx=&x[Offst*fr]; double* lph=&ph[Offst*(fr-frst)]; for (int i=0; i<Wid; i++) y[i]=cdouble(lx[i]).rotate(-lph[i]+i*0.15*2*M_PI); CFFTCW(y, win, Amp, 0, log2(Wid), W, X); int pf=0.15*Wid, mpf=pf; for (int k=pf-4; k<=pf+4; k++) if (Amp[k]>Amp[mpf]) mpf=k; if (mpf>pf-4 && mpf<pf+4) pf=mpf; double lfs=pf, lphs; LSESinusoid(lfs, pf-3, pf+3, X, Wid, 3, M, c, iH2, as[fr], lphs, 1e-3); fs[fr]=fs[fr]+lfs/Wid-0.15; phs[fr]+=lphs-0.15*Wid*M_PI; as[fr]*=2; } delete[] y; delete[] f; delete[] win; delete[] fa; FreeFFTBuffer(Amp); }//MultiplicativeUpdateF //--------------------------------------------------------------------------- /* Earlier reestimation method routines. Further reading: Wen X. and M. Sandler, "Evaluating parameters of time-varying sinusoids by demodulation," in Proc. DAFx'08, Espoo, 2008. */ /* function ReEstFreq: sinusoid reestimation by demodulating frequency. In: x[Wid+Offst*(FrCount-1)]: waveform data FrCount, Wid, Offst: frame count, frame size and hop size fbuf[FrCount], ns[FrCount]: initial frequency estiamtes and their timing win[Wid]: window function for estimating demodulated sinusoid M, c[], iH2: cosine-family window specification parameters, must be consistent with win[] Wids[FrCount]: specifies frame sizes for estimating individual frames of demodulated sinusoid, optional w[Wid/2], ps[Wid], xs[Wid], xc[Wid], fa[FrCount-1], fb[FrCount-1], fc[FrCount-1], fd[FrCount-1]: buffers Out: fbuf[FrCount], abuf[FrCount], pbuf[FrCount]: reestimated frequencies, amplitudes and phase angles No return value. */ void ReEstFreq(int FrCount, int Wid, int Offst, double* x, double* fbuf, double* abuf, double* pbuf, double* win, int M, double* c, double iH2, cdouble* w, cdouble* xc, cdouble* xs, double* ps, double* fa, double* fb, double* fc, double* fd, double* ns, int* Wids) { int hWid=Wid/2; //reestimate using frequency track CubicSpline(FrCount-1, fa, fb, fc, fd, ns, fbuf, 0, 1); for (int fr=0; fr<FrCount; fr++) { //find ps if (fr==0) { double lfd=0, lfc=fc[0], lfb=fb[0], lfa=fa[0]; for (int j=0; j<Wid; j++) { double lx=j-hWid; ps[j]=2*M_PI*lx*(lfd+lx*(lfc/2+lx*(lfb/3+lx*lfa/4))); } // memset(ps, 0, sizeof(double)*hWid); } else if (fr==FrCount-1) { int lfr=FrCount-2; double lfc=fc[lfr], lfb=fb[lfr], lfa=fa[lfr]; double lfd=-(hWid*(lfc+hWid*(lfb+hWid*lfa))); ps[0]=-2*M_PI*hWid*(lfd+hWid*(lfc/2+hWid*(lfb/3+hWid*lfa/4))); for (int j=1; j<Wid; j++) { ps[j]=ps[0]+2*M_PI*j*(lfd+j*(lfc/2+j*(lfb/3+j*lfa/4))); } // memset(&ps[hWid], 0, sizeof(double)*hWid); } else { int lfr=fr-1; double lfd=fd[lfr]-fd[fr], lfc=fc[lfr], lfb=fb[lfr], lfa=fa[lfr]; ps[0]=-2*M_PI*hWid*(lfd+hWid*(lfc/2+hWid*(lfb/3+hWid*lfa/4))); for (int j=1; j<hWid+1; j++) { ps[j]=ps[0]+2*M_PI*j*(lfd+j*(lfc/2+j*(lfb/3+j*lfa/4))); } lfr=fr; lfd=0, lfc=fc[lfr], lfb=fb[lfr], lfa=fa[lfr]; for (int j=1; j<hWid; j++) { ps[j+hWid]=2*M_PI*j*(lfd+j*(lfc/2+j*(lfb/3+j*lfa/4))); } } double* ldata=&x[fr*Offst]; for (int j=0; j<Wid; j++) { xs[j].x=ldata[j]*cos(-ps[j]); xs[j].y=ldata[j]*sin(-ps[j]); } if (Wids) { int lWid=Wids[fr], lhWid=Wids[fr]/2, lM; SetTwiddleFactors(lWid, w); double *lwin=NewWindow(wtHann, lWid), lc[4], liH2; windowspec(wtHann, lWid, &lM, lc, &liH2); CFFTCW(&xs[hWid-lhWid], lwin, NULL, NULL, log2(lWid), w, xc); delete[] lwin; double lf=fbuf[fr]*lWid, la, lp; LSESinusoid(lf, lf-3, lf+3, xc, lWid, 3, lM, lc, liH2, la, lp, 1e-3); if (la*2>abuf[fr]) fbuf[fr]=lf/lWid, abuf[fr]=la*2, pbuf[fr]=lp; } else { CFFTCW(xs, win, NULL, NULL, log2(Wid), w, xc); double lf=fbuf[fr]*Wid, la, lp; LSESinusoid(lf, lf-3, lf+3, xc, Wid, 3, M, c, iH2, la, lp, 1e-3); if (la*2>abuf[fr]) fbuf[fr]=lf/Wid, abuf[fr]=la*2, pbuf[fr]=lp; } } }//ReEstFreq /* function ReEstFreq_2: sinusoid reestimation by demodulating frequency. This is that same as ReEstFreq(...) except that it calls Sinusoid(...) to synthesize the phase track used for demodulation and that it does not allow variable window sizes for estimating demodulated sinusoid. In: x[Wid+Offst*(FrCount-1)]: waveform data FrCount, Wid, Offst: frame count, frame size and hop size fbuf[FrCount], ns[FrCount]: initial frequency estiamtes and their timing win[Wid]: window function for LSE sinusoid estimation M, c[], iH2: cosine-family window specification parameters, must be consistent with M, c, iH2 w[Wid/2], xs[Wid], xc[Wid], f3[FrCount-1], f2[FrCount-1], f1[FrCount-1], f0[FrCount-1]: buffers Out: fbuf[FrCount], abuf[FrCount], pbuf[FrCount]: reestimated frequencies, amplitudes and phase angles No return value. */ void ReEstFreq_2(int FrCount, int Wid, int Offst, double* x, double* fbuf, double* abuf, double* pbuf, double* win, int M, double* c, double iH2, cdouble* w, cdouble* xc, cdouble* xs, double* f3, double* f2, double* f1, double* f0, double* ns) { int hWid=Wid/2; //reestimate using frequency track CubicSpline(FrCount-1, f3, f2, f1, f0, ns, fbuf, 1, 1); double *refcos=(double*)malloc8(sizeof(double)*Wid), *refsin=&refcos[hWid], ph=0, centralph; memset(f0, 0, sizeof(double)*FrCount); int N=Wid+Offst*(FrCount-1); double* cosine=new double[N], *sine=new double[N]; Sinusoid(&cosine[hWid], &sine[hWid], -hWid, 0, f3[0], f2[0], f1[0], f0[0], ph); for (int fr=0; fr<FrCount-1; fr++) { int ncentre=hWid+Offst*fr; if (fr==FrCount-2) Sinusoid(&cosine[ncentre], &sine[ncentre], 0, Wid, f3[fr], f2[fr], f1[fr], f0[fr], ph); else Sinusoid(&cosine[ncentre], &sine[ncentre], 0, hWid, f3[fr], f2[fr], f1[fr], f0[fr], ph); } double err=0; for (int n=0; n<N; n++) {double tmp=cosine[n]-x[n-hWid]; err+=tmp*tmp; tmp=cosine[n]*cosine[n]+sine[n]*sine[n]-1; err+=tmp*tmp;} ph=0; for (int fr=0; fr<FrCount; fr++) { double* ldata=&x[fr*Offst-hWid]; //store first half of demodulated frame to xs[0:hWid-1] if (fr==0) { Sinusoid(&refcos[hWid], &refsin[hWid], -hWid, 0, f3[0], f2[0], f1[0], f0[0], ph); for (int i=0; i<hWid; i++) xs[i].x=ldata[i]*refcos[i], xs[i].y=-ldata[i]*refsin[i]; } else { ph=0; Sinusoid(refcos, refsin, 0, hWid, f3[fr-1], f2[fr-1], f1[fr-1], f0[fr-1], ph); for (int i=0; i<hWid; i++) xs[i].x=ldata[i]*refcos[i], xs[i].y=-ldata[i]*refsin[i]; } //taking care of phase angles if (fr==FrCount-1) {double tmp=ph; ph=centralph; centralph=tmp;} else centralph=ph; double *lrefcos=&refcos[-hWid], *lrefsin=&refsin[-hWid]; //store second half of demodulated frame to xs[hWid:Wid-1] if (fr==FrCount-1) { Sinusoid(lrefcos, lrefsin, hWid, Wid, f3[FrCount-2], f2[FrCount-2], f1[FrCount-2], f0[FrCount-2], ph); for (int i=hWid; i<Wid; i++) xs[i].x=ldata[i]*lrefcos[i], xs[i].y=-ldata[i]*lrefsin[i]; } else { Sinusoid(refcos, refsin, 0, hWid, f3[fr], f2[fr], f1[fr], f0[fr], ph); for (int i=hWid; i<Wid; i++) xs[i].x=ldata[i]*lrefcos[i], xs[i].y=-ldata[i]*lrefsin[i]; } CFFTCW(xs, win, NULL, NULL, log2(Wid), w, xc); double lf=fbuf[fr]*Wid, la, lp; LSESinusoid(lf, lf-3, lf+3, xc, Wid, 3, M, c, iH2, la, lp, 1e-3); if (la*2>abuf[fr]) fbuf[fr]=lf/Wid, abuf[fr]=la*2, pbuf[fr]=lp+centralph; } }//ReEstFreq_2 /* function ReEstFreqAmp: sinusoid reestimation by demodulating frequency and amplitude. In: x[Wid+Offst*(FrCount-1)]: waveform data FrCount, Wid, Offst: frame count, frame size and hop size fbuf[FrCount], abuf[FrCount], ns[FrCount]: initial frequency and amplitude estiamtes and their timing win[Wid]: window function for estimating demodulated sinusoid M, c[], iH2: cosine-family window specification parameters, must be consistent with win[] Wids[FrCount]: specifies frame sizes for estimating individual frames of demodulated sinusoid, optional w[Wid/2], ps[Wid], xs[Wid], xc[Wid]: buffers fa[FrCount-1], fb[FrCount-1], fc[FrCount-1], fd[FrCount-1]: buffers aa[FrCount-1], ab[FrCount-1], ac[FrCount-1], ad[FrCount-1]: buffers Out: fbuf[FrCount], abuf[FrCount], pbuf[FrCount]: reestimated frequencies, amplitudes and phase angles No return value. */ void ReEstFreqAmp(int FrCount, int Wid, int Offst, double* x, double* fbuf, double* abuf, double* pbuf, double* win, int M, double* c, double iH2, cdouble* w, cdouble* xc, cdouble* xs, double* ps, double* as, double* fa, double* fb, double* fc, double* fd, double* aa, double* ab, double* ac, double* ad, double* ns, int* Wids) { int hWid=Wid/2; //reestimate using amplitude and frequency track CubicSpline(FrCount-1, fa, fb, fc, fd, ns, fbuf, 0, 1); CubicSpline(FrCount-1, aa, ab, ac, ad, ns, abuf, 0, 1); for (int fr=0; fr<FrCount; fr++) { if (fr==0) { double lfd=0, lfc=fc[0], lfb=fb[0], lfa=fa[0], lad=ad[0], lac=ac[0], lab=ab[0], laa=aa[0]; for (int j=0; j<Wid; j++) { double lx=j-hWid; ps[j]=2*M_PI*lx*(lfd+lx*(lfc/2+lx*(lfb/3+lx*lfa/4))); } for (int j=0; j<Wid; j++) { double lx=j-hWid; as[j]=lad+lx*(lac+lx*(lab+lx*laa)); } } else if (fr==FrCount-1) { int lfr=FrCount-2; double lfc=fc[lfr], lfb=fb[lfr], lfa=fa[lfr]; double lfd=-(hWid*(lfc+hWid*(lfb+hWid*lfa))); double lad=ad[lfr], lac=ac[lfr], lab=ab[lfr], laa=aa[lfr]; ps[0]=-2*M_PI*hWid*(lfd+hWid*(lfc/2+hWid*(lfb/3+hWid*lfa/4))); for (int j=1; j<Wid; j++) { ps[j]=ps[0]+2*M_PI*j*(lfd+j*(lfc/2+j*(lfb/3+j*lfa/4))); } as[0]=ad[lfr]; for (int j=0; j<Wid; j++) { as[j]=lad+j*(lac+j*(lab+j*laa)); } } else { int lfr=fr-1; double lfd=fd[lfr]-fd[fr], lfc=fc[lfr], lfb=fb[lfr], lfa=fa[lfr]; double lad=ad[lfr], lac=ac[lfr], lab=ab[lfr], laa=aa[lfr]; ps[0]=-2*M_PI*hWid*(lfd+hWid*(lfc/2+hWid*(lfb/3+hWid*lfa/4))); for (int j=0; j<hWid+1; j++) { ps[j]=ps[0]+2*M_PI*j*(lfd+j*(lfc/2+j*(lfb/3+j*lfa/4))); as[j]=lad+j*(lac+j*(lab+j*laa)); } lfr=fr; lfd=0, lfc=fc[lfr], lfb=fb[lfr], lfa=fa[lfr]; lad=ad[lfr], lac=ac[lfr], lab=ab[lfr], laa=aa[lfr]; for (int j=1; j<hWid; j++) { ps[j+hWid]=2*M_PI*j*(lfd+j*(lfc/2+j*(lfb/3+j*lfa/4))); as[j+hWid]=lad+j*(lac+j*(lab+j*laa)); } } double *ldata=&x[fr*Offst]; for (int j=0; j<Wid; j++) { double tmp; if ((fr==0 && j<hWid) || (fr==FrCount-1 && j>=hWid)) tmp=1; else if (as[hWid]>100*as[j]) tmp=100; else tmp=as[hWid]/as[j]; tmp=tmp*ldata[j]; xs[j].x=tmp*cos(-ps[j]); xs[j].y=tmp*sin(-ps[j]); } if (Wids) { int lWid=Wids[fr], lhWid=Wids[fr]/2, lM; SetTwiddleFactors(lWid, w); double *lwin=NewWindow(wtHann, lWid), lc[4], liH2; windowspec(wtHann, lWid, &lM, lc, &liH2); CFFTCW(&xs[hWid-lhWid], lwin, NULL, NULL, log2(lWid), w, xc); delete[] lwin; double lf=fbuf[fr]*lWid, la, lp; LSESinusoid(lf, lf-3, lf+3, xc, lWid, 3, lM, lc, liH2, la, lp, 1e-3); if (la*2>abuf[fr]) fbuf[fr]=lf/lWid, abuf[fr]=la*2, pbuf[fr]=lp; } else { CFFTCW(xs, win, NULL, NULL, log2(Wid), w, xc); double lf=fbuf[fr]*Wid, la, lp; LSESinusoid(lf, lf-3, lf+3, xc, Wid, 3, M, c, iH2, la, lp, 1e-3); if (la*2>abuf[fr]) fbuf[fr]=lf/Wid, abuf[fr]=la*2, pbuf[fr]=lp; } } }//ReEstFreqAmp /* function Reestimate2: iterative demodulation method for sinusoid parameter reestimation. In: x[(FrCount-1)*Offst+Wid]: waveform data FrCount, Wid, Offst: frame count, frame size and hop size win[Wid]: window function M, c[], iH2: cosine-family window specification parameters, must be consistent with win[] Wids[FrCount]: specifies frame sizes for estimating individual frames of demodulated sinusoid, optional maxiter: maximal number of iterates ae[FrCount], fe[FrCount], pe[FrCount]: initial amplitude, frequency and phase estimates Out: aret[FrCount], fret[FrCount], pret[FrCount]: reestimated amplitudes, frequencies and phase angles Returns the number of unused iterates left of the total of maxiter. */ int Reestimate2(int FrCount, int Wid, int Offst, double* win, int M, double* c, double iH2, double* x, double* ae, double* fe, double* pe, double* aret, double* fret, double *pret, int maxiter, int* Wids) { AllocateFFTBuffer(Wid, fft, w, xc); double convep=1e-4, dif=0, lastdif=0; //convep is the hard-coded threshold that stops the iteration int iter=1, hWid=Wid/2; double *ns=new double[FrCount*12], *as=new double[Wid*5]; double *fbuf=&ns[FrCount], *abuf=&ns[FrCount*2], *aa=&ns[FrCount*3], *ab=&ns[FrCount*4], *ac=&ns[FrCount*5], *ad=&ns[FrCount*6], *fa=&ns[FrCount*7], *fb=&ns[FrCount*8], *fc=&ns[FrCount*9], *fd=&ns[FrCount*10], *pbuf=&ns[FrCount*11]; double *ps=&as[Wid]; cdouble *xs=(cdouble*)&as[Wid*3]; memcpy(fbuf, fe, sizeof(double)*FrCount); memcpy(abuf, ae, sizeof(double)*FrCount); memcpy(pbuf, pe, sizeof(double)*FrCount); for (int i=0; i<FrCount; i++) { ns[i]=hWid+i*Offst; } while (iter<=maxiter) { ReEstFreq(FrCount, Wid, Offst, x, fbuf, abuf, pbuf, win, M, c, iH2, w, xc, xs, ps, fa, fb, fc, fd, ns, Wids); ReEstFreq(FrCount, Wid, Offst, x, fbuf, abuf, pbuf, win, M, c, iH2, w, xc, xs, ps, fa, fb, fc, fd, ns, Wids); ReEstFreqAmp(FrCount, Wid, Offst, x, fbuf, abuf, pbuf, win, M, c, iH2, w, xc, xs, ps, as, fa, fb, fc, fd, aa, ab, ac, ad, ns, Wids); if (iter>1) lastdif=dif; dif=0; if (iter==1) { for (int fr=0; fr<FrCount; fr++) { if (fabs(abuf[fr])>fabs(ae[fr])) dif+=fabs(fe[fr]-fbuf[fr])*Wid+fabs((ae[fr]-abuf[fr])/abuf[fr]); else dif+=fabs(fe[fr]-fbuf[fr])*Wid+fabs((ae[fr]-abuf[fr])/ae[fr]); } } else { for (int fr=0; fr<FrCount; fr++) { if (fabs(abuf[fr])>fabs(aret[fr])) dif+=fabs(fret[fr]-fbuf[fr])*Wid+fabs((aret[fr]-abuf[fr])/abuf[fr]); else dif+=fabs(fret[fr]-fbuf[fr])*Wid+fabs((aret[fr]-abuf[fr])/aret[fr]); } } memcpy(fret, fbuf, sizeof(double)*FrCount); memcpy(aret, abuf, sizeof(double)*FrCount); dif/=FrCount; if (fabs(dif)<convep || (iter>1 && fabs(dif-lastdif)<convep*lastdif)) break; iter++; } memcpy(pret, pbuf, sizeof(double)*FrCount); delete[] ns; delete[] as; delete[] fft; return maxiter-iter; }//Reestimate2 //--------------------------------------------------------------------------- /* Derivative method as proposed in DAFx09 Further reading: Wen X. and M. Sandler, "Notes on model-based non-stationary sinusoid estimation methods using derivatives," in Proc. DAFx'09, Como, 2009. */ /* function Derivative: derivative method for estimating amplitude derivative, frequency, and frequency derivative given signal and its derivatives. In: x[Wid], dx[Wid], ddx[Wid]: waveform and its derivatives win[Wid]: window function f0: initial digital frequency estimate Out: f0: new estimate of digital frequency f1, a1: estimates of frequency and amplitude derivatives No return value. */ void Derivative(int Wid, double* win, cdouble* x, cdouble* dx, cdouble* ddx, double& f0, double* f1, double* a0, double* a1, double* ph) { AllocateFFTBuffer(Wid, fft, W, X); CFFTCW(x, win, fft, NULL, log2(Wid), W, X); int m=f0*Wid, m0=m-10, m1=m+10, hWid=Wid/2; if (m0<0) m0=0; if (m1>hWid) m1=hWid; for (int n=m0; n<=m1; n++) if (fft[n]>fft[m]) m=n; cdouble Sw=0, S1w=0, S2w=0; for (int n=0; n<Wid; n++) { cdouble tmp=x[n]*win[n]; Sw+=tmp.rotate(-2*M_PI*m*(n-hWid)/Wid); tmp=dx[n]*win[n]; S1w+=tmp.rotate(-2*M_PI*m*(n-hWid)/Wid); } double omg0=(S1w/Sw).y; Sw=0, S1w=0; for (int n=0; n<Wid; n++) { cdouble tmp=x[n]*win[n]; Sw+=tmp.rotate(-omg0*(n-hWid)/Wid); tmp=dx[n]*win[n]; S1w+=tmp.rotate(-omg0*(n-hWid)/Wid); tmp=ddx[n]*win[n]; S2w+=tmp.rotate(-omg0*(n-hWid)/Wid); } omg0=(S1w/Sw).y; double miu0=(S1w/Sw).x; double psi0=(S2w/Sw).y-2*miu0*omg0; f0=omg0/(2*M_PI); *f1=psi0/(2*M_PI); *a1=miu0; FreeFFTBuffer(fft); }//Derivative /* function Xkw: computes windowed spectrum of x and its derivatives up to order K at angular frequency omg, from x using window w and its derivatives. In: x[Wid]: waveform data w[K+1][Wid]: window functions and its derivatives up to order K omg: angular frequency Out: X[K+1]: windowed spectrum and its derivatives up to order K No return value. This function is for internal use. */ void Xkw(cdouble* X, int K, int Wid, double* x, double** w, double omg) { int hWid=Wid/2; //calculate the first row memset(X, 0, sizeof(cdouble)*(K+1)); for (int i=0; i<Wid; i++) { double n=i-hWid; double ph=omg*n; for (int k=0; k<=K; k++) { cdouble tmp=x[i]*w[k][i]; X[k]+=tmp.rotate(-ph); } } //calculate the rest rows for (int k=1; k<=K; k++) { cdouble *thisX=&X[k], *lastX=&X[k-1]; for (int kk=K-k; kk>=0; kk--) thisX[kk]=-lastX[kk+1]+cdouble(0, omg)*lastX[kk]; } }//Xkw /* function Xkw: computes windowed spectrum of x and its derivatives up to order K at angular frequency omg, from x and its derivatives using window w. In: x[K+1][Wid]: waveform data and its derivatives up to order K. w[Wid]: window function omg: angular frequency Out: X[K+1]: windowed spectrum and its derivatives up to order K No return value. This function is for testing only. */ void Xkw(cdouble* X, int K, int Wid, double** x, double* w, double omg) { int hWid=Wid/2; memset(X, 0, sizeof(cdouble)*(K+1)); for (int i=0; i<Wid; i++) { double n=i-hWid; double ph=omg*n; for (int k=0; k<=K; k++) { cdouble tmp=x[k][i]*w[i]; X[k]+=tmp.rotate(-ph); } } }//Xkw /* function Derivative: derivative method for estimating the model log(s)=h[M]'r[M], by discarding extra equations In: s[Wid]: waveform data win[][Wid]: window function and its derivatives h[M], dh[M]: pointers to basis functions and their derivatives harg: pointer argument to be used by calls to functions in h[] amd dh[]. p0[p0s]: zero-constraints on real parts of r, i.e. Re(r[p0[*]]) are constrained to 0. q0[q0s]: zero-constraints on imaginary parts of r, i.e. Im(r[q0[*]]) are constrained to 0. omg: initial angular frequency Out: r[M]: estimated coefficients to h[M]. No return value. */ void Derivative(int M, double (**h)(double t, void*), double (**dh)(double t, void*), cdouble* r, int p0s, int* p0, int q0s, int* q0, int Wid, double* s, double** win, double omg, void* harg) { int hWid=Wid/2, M1=M-1; int Kr=(M1)*2-p0s-q0s; //number of real unknowns apart from p0 and q0 int Kc=ceil(Kr/2.0); //number of derivatives required //ind marks the 2*M1 real elements of an M1-array of complex unknowns with // numerical indices (0-based) or -1 if it is not a real unknown variable //uind marks the Kr real unknowns with their positions in ind int *uind=new int[Kr], *ind=new int[2*M1]; memset(ind, 0, sizeof(int)*2*M1); for (int p=0; p<p0s; p++) ind[2*(p0[p]-1)]=-1; for (int q=0; q<q0s; q++) ind[2*(q0[q]-1)+1]=-1; { int p=0, up=0; while (p<2*M1) { if (ind[p]>=0) { uind[up]=p; ind[p]=up; up++; } p++; } if (up!=Kr) throw(""); } cdouble* Skw=new cdouble[M]; Xkw(Skw, Kc, Wid, s, win, omg); double* x=new double[Wid]; cdouble** Allocate2(cdouble, M, Kc, Smkw); for (int m=1; m<M; m++) { for (int i=0; i<Wid; i++) x[i]=dh[m](i-hWid, harg)*s[i]; Xkw(Smkw[m], Kc-1, Wid, x, win, omg); } //allocate buffer for linear system A(pq)=b Alloc2(2*Kc+2, Kr, A); double** AA; double *bb, *pqpq; double *b=A[2*Kc], *pq=A[2*Kc+1]; for (int k=0; k<Kr; k++) b[k]=((double*)(&Skw[1]))[k]; // *pq=(double*)(&r[1]); for (int k=0; k<Kc; k++) //looping through rows of A { //columns of A includes rows of Smkw corresponding to real unknowns for (int m=0; m<M1; m++) { int lind; if ((lind=ind[2*m])>=0) //the real part being unknown { A[2*k][lind]=Smkw[m+1][k].x; A[2*k+1][lind]=Smkw[m+1][k].y; } if ((lind=ind[2*m+1])>=0) //the imag part being unknown { A[2*k+1][lind]=Smkw[m+1][k].x; A[2*k][lind]=-Smkw[m+1][k].y; } } } bool dropeq=(2*Kc-1==Kr); if (dropeq) { Allocate2(double, Kr+2, Kr, AA); bb=AA[Kr], pqpq=AA[Kr+1]; memcpy(AA[0], A[0], sizeof(double)*Kr*(Kr-1)); memcpy(AA[Kr-1], A[Kr], sizeof(double)*Kr); memcpy(bb, b, sizeof(double)*(Kr-1)); bb[Kr-1]=((double*)(&Skw[1]))[Kr]; } double det; GECP(Kr, pq, A, b, &det); if (dropeq) { double det2; GECP(Kr, pqpq, AA, bb, &det2); if (fabs(det2)>fabs(det)) memcpy(pq, pqpq, sizeof(double)*Kr); DeAlloc2(AA); } memset(&r[1], 0, sizeof(double)*M1*2); for (int k=0; k<Kr; k++) ((double*)(&r[1]))[uind[k]]=pq[k]; //estiamte r0 cdouble e0=0; for (int i=0; i<Wid; i++) { cdouble expo=0; double n=i-hWid; for (int m=1; m<M; m++){double lhm=h[m](n, harg); expo+=r[m]*lhm;} cdouble tmp=exp(expo)*win[0][i]; e0+=tmp.rotate(-omg*n); } r[0]=log(Skw[0]/e0); delete[] x; delete[] Skw; delete[] uind; delete[] ind; DeAlloc2(Smkw); DeAlloc2(A); }//Derivative*/ /* function DerivativeLS: derivative method for estimating the model log(s)=h[M]'r[M], least-square implementation In: s[Wid]: waveform data win[][Wid]: window function and its derivatives h[M], dh[M]: pointers to basis functions and their derivatives harg: pointer argument to be used by calls to functions in h[] amd dh[]. K: number of derivatives to take p0[p0s]: zero-constraints on real parts of r, i.e. Re(r[p0[*]]) are constrained to 0. q0[q0s]: zero-constraints on imaginary parts of r, i.e. Im(r[q0[*]]) are constrained to 0. omg: initial angular frequency Out: r[M]: estimated coefficients to h[M]. No return value. */ void DerivativeLS(int K, int M, double (**h)(double t, void* harg), double (**dh)(double t, void* harg), cdouble* r, int p0s, int* p0, int q0s, int* q0, int Wid, double* s, double** win, double omg, void* harg, bool r0) { int hWid=Wid/2, M1=M-1; int Kr=(M1)*2-p0s-q0s; //number of real unknowns apart from p0 and q0 int Kc=ceil(Kr/2.0); //number of derivatives required if (Kc<K) Kc=K; int *uind=new int[Kr], *ind=new int[2*M1]; memset(ind, 0, sizeof(int)*2*M1); for (int p=0; p<p0s; p++) ind[2*(p0[p]-1)]=-1; for (int q=0; q<q0s; q++) ind[2*(q0[q]-1)+1]=-1; {int p=0, up=0; while (p<2*M1){if (ind[p]>=0){uind[up]=p; ind[p]=up; up++;} p++;} if (up!=Kr) throw("");} //allocate buffer for linear system A(pq)=b cdouble* Skw=new cdouble[Kc+1]; double* x=new double[Wid]; cdouble** Allocate2(cdouble, M, Kc, Smkw); Alloc2(2*Kc+2, 2*Kc, A); double *b=A[2*Kc], *pq=A[2*Kc+1]; Xkw(Skw, Kc, Wid, s, win, omg); for (int m=1; m<M; m++) { for (int i=0; i<Wid; i++) x[i]=dh[m](i-hWid, harg)*s[i]; Xkw(Smkw[m], Kc-1, Wid, x, win, omg); } for (int k=0; k<2*Kc; k++) b[k]=((double*)(&Skw[1]))[k]; for (int k=0; k<Kc; k++) { for (int m=0; m<M1; m++) { int lind; if ((lind=ind[2*m])>=0) { A[2*k][lind]=Smkw[m+1][k].x; A[2*k+1][lind]=Smkw[m+1][k].y; } if ((lind=ind[2*m+1])>=0) { A[2*k+1][lind]=Smkw[m+1][k].x; A[2*k][lind]=-Smkw[m+1][k].y; } } } if (2*Kc==Kr) GECP(Kr, pq, A, b); else LSLinear2(2*Kc, Kr, pq, A, b); memset(&r[1], 0, sizeof(double)*M1*2); for (int k=0; k<Kr; k++) ((double*)(&r[1]))[uind[k]]=pq[k]; //estiamte r0 if (r0) { cdouble e0=0; for (int i=0; i<Wid; i++) { cdouble expo=0; double n=i-hWid; for (int m=1; m<M; m++){double lhm=h[m](n, harg); expo+=r[m]*lhm;} cdouble tmp=exp(expo)*win[0][i]; e0+=tmp.rotate(-omg*n); } r[0]=log(Skw[0]/e0); } delete[] x; delete[] Skw; delete[] uind; delete[] ind; DeAlloc2(Smkw); DeAlloc2(A); }//DerivativeLS /* function DerivativeLS: derivative method for estimating the model log(s)=h[M]'r[M] using Fr measurement points a quarter of Wid apart from each other, implemented by least-square. In: s[Wid+(Fr-1)*Wid/4]: waveform data win[][Wid]: window function and its derivatives h[M], dh[M]: pointers to basis functions and their derivatives harg: pointer argument to be used by calls to functions in h[] amd dh[]. Fr: number of measurement points K: number of derivatives to take at each measurement point p0[p0s]: zero-constraints on real parts of r, i.e. Re(r[p0[*]]) are constrained to 0. q0[q0s]: zero-constraints on imaginary parts of r, i.e. Im(r[q0[*]]) are constrained to 0. omg: initial angular frequency r0: specifies if r[0] is to be computed. Out: r[M]: estimated coefficients to h[M]. No return value. */ void DerivativeLS(int Fr, int K, int M, double (**h)(double t, void* harg), double (**dh)(double t, void* harg), cdouble* r, int p0s, int* p0, int q0s, int* q0, int Wid, double* s, double** win, double omg, void* harg, bool r0) { int hWid=Wid/2, qWid=Wid/4, M1=M-1; int Kr=(M1)*2-p0s-q0s; //number of real unknowns apart from p0 and q0 int Kc=ceil(Kr/2.0/Fr); //number of derivatives required if (Kc<K) Kc=K; int *uind=new int[Kr], *ind=new int[2*M1]; memset(ind, 0, sizeof(int)*2*M1); for (int p=0; p<p0s; p++) ind[2*(p0[p]-1)]=-1; for (int q=0; q<q0s; q++) ind[2*(q0[q]-1)+1]=-1; {int p=0, up=0; while (p<2*M1){if (ind[p]>=0){uind[up]=p; ind[p]=up; up++;} p++;}} //allocate buffer for linear system A(pq)=b cdouble* Skw=new cdouble[Kc+1], Skw00; double* x=new double[Wid]; cdouble** Allocate2(cdouble, M, Kc, Smkw); Alloc2(2*Fr*Kc, 2*Fr*Kc, A); double *pq=new double[2*Fr*Kc], *b=new double[2*Fr*Kc]; for (int fr=0; fr<Fr; fr++) { int Offst=qWid*fr; double* ss=&s[Offst]; Xkw(Skw, Kc, Wid, ss, win, omg); if (fr==0) Skw00=Skw[0]; for (int m=1; m<M; m++) { for (int i=0; i<Wid; i++) x[i]=dh[m](i+Offst-hWid, harg)*ss[i]; Xkw(Smkw[m], Kc-1, Wid, x, win, omg); } for (int k=0; k<2*Kc; k++) b[2*fr*Kc+k]=((double*)(&Skw[1]))[k]; for (int k=0; k<Kc; k++) { for (int m=0; m<M1; m++) { int lind; if ((lind=ind[2*m])>=0) { A[2*fr*Kc+2*k][lind]=Smkw[m+1][k].x; A[2*fr*Kc+2*k+1][lind]=Smkw[m+1][k].y; } if ((lind=ind[2*m+1])>=0) { A[2*fr*Kc+2*k+1][lind]=Smkw[m+1][k].x; A[2*fr*Kc+2*k][lind]=-Smkw[m+1][k].y; } } } } if (2*Fr*Kc==Kr) GECP(Kr, pq, A, b); else LSLinear2(2*Fr*Kc, Kr, pq, A, b); memset(&r[1], 0, sizeof(double)*M1*2); for (int k=0; k<Kr; k++) ((double*)(&r[1]))[uind[k]]=pq[k]; //estiamte r0 if (r0) { cdouble e0=0; for (int i=0; i<Wid; i++) { cdouble expo=0; double n=i-hWid; for (int m=1; m<M; m++){double lhm=h[m](n, harg); expo+=r[m]*lhm;} cdouble tmp=exp(expo)*win[0][i]; e0+=tmp.rotate(-omg*n); } r[0]=log(Skw00/e0); } delete[] x; delete[] Skw; delete[] uind; delete[] ind; DeAlloc2(Smkw); DeAlloc2(A); delete[] pq; delete[] b; }//DerivativeLS //--------------------------------------------------------------------------- /* Abe-Smith sinusoid estimator 2005 Further reading: M. Abe and J. O. Smith III, ¡°AM/FM rate estimation for time-varying sinusoidal modeling,¡± in Proc. ICASSP'05, Philadelphia, 2005. */ /* function RDFTW: windowed DTFT at frequency k bins In: data[Wid]: waveform data w[Wid]: window function k: frequency, in bins Out: Xr, Xi: real and imaginary parts of the DTFT of xw at frequency k bins No return value. */ void RDFTW(double& Xr, double& Xi, double k, int Wid, double* data, double* w) { Xr=Xi=0; int hWid=Wid/2; double* lw=&w[Wid]; for (int i=0; i<=Wid; i++) { double tmp; tmp=*data**lw; data++, lw--; //* double ph=-2*M_PI*(i-hWid)*k/Wid; Xr+=tmp*cos(ph); Xi+=tmp*sin(ph); //*/ } }//RDFTW /* function TFAS05: the Abe-Smith method 2005 In: data[Wid]: waveform data w[Wid]: window function res: resolution of frequency for QIFFT Out: f, a, ph: frequency, amplitude and phase angle estimates aesp, fslope: estimates of log amplitude and frequency derivatives No return value. */ void TFAS05(double& f, double& t, double& a, double& ph, double& aesp, double& fslope, int Wid, double* data, double* w, double res) { double fi=floor(f*Wid+0.5); //frequency (int) in bins double xr0, xi0, xr_1, xi_1, xr1, xi1; RDFTW(xr0, xi0, fi, Wid, data, w); RDFTW(xr_1, xi_1, fi-res, Wid, data, w); RDFTW(xr1, xi1, fi+res, Wid, data, w); double winnorm=0; for (int i=0; i<=Wid; i++) winnorm+=w[i]; double y0=log(sqrt(xr0*xr0+xi0*xi0)/winnorm), y_1=log(sqrt(xr_1*xr_1+xi_1*xi_1)/winnorm), y1=log(sqrt(xr1*xr1+xi1*xi1)/winnorm); double df=0; //* if (y0<y1) { double newfi=fi+res; while (y0<y1) { y_1=y0, xr_1=xr0, xi_1=xi0; y0=y1, xr0=xr1, xi0=xi1; newfi+=res; RDFTW(xr1, xi1, newfi, Wid, data, w); y1=log(sqrt(xr1*xr1+xi1*xi1)/winnorm); fi+=res; } } else if(y0<y_1) { double newfi=fi-res; while (y0<y_1) { y1=y0, xr1=xr0, xi1=xi0; y0=y_1, xr0=xr_1, xi0=xi_1; newfi-=res; RDFTW(xr_1, xi_1, newfi, Wid, data, w); y_1=log(sqrt(xr_1*xr_1+xi_1*xi_1)/winnorm); fi-=res; } } //*/ double a2=(y1+y_1)*0.5-y0, a1=(y1-y_1)*0.5, a0=y0; df=-a1*0.5/a2; f=fi+df*res; //in bins double y=a0-0.25*a1*a1/a2; a=exp(y); double ph0=(xi0==0 && xr0==0)?0:atan2(xi0, xr0), ph_1=(xi_1==0 && xr_1==0)?0:atan2(xi_1, xr_1), ph1=(xi1==0 && xr1==0)?0:atan2(xi1, xr1); if (fabs(ph_1-ph0)>M_PI) { if (ph_1-ph0>0) ph_1-=M_PI*2; else ph_1+=M_PI*2; } if (fabs(ph1-ph0)>M_PI) { if (ph1-ph0>0) ph1-=M_PI*2; else ph1+=M_PI*2; } double b2=(ph1+ph_1)*0.5-ph0, b1=(ph1-ph_1)*0.5, b0=ph0; ph=b0+b1*(df+b2*df); //now we have the QI estimates double uff=2*a2, vf=b1+2*b2*df, vff=2*b2; double dfdp=Wid/(2*M_PI*res); double upp=uff*dfdp*dfdp, vp=vf*dfdp, vpp=vff*dfdp*dfdp; double p=-upp*0.5/(upp*upp+vpp*vpp); double alf=-2*p*vp, beta=p*vpp/upp; //*direct method double beta_p=beta/p; double feses=f-alf*beta/p /(2*M_PI)*Wid, yeses=y-alf*alf*0.25/p+0.25*log(1+beta_p*beta_p), pheses=ph+alf*alf*beta*0.25/p-0.5*atan(beta_p); //*/ /*adapted method double zt[]={0, 0.995354, 0.169257, 1.393056, 0.442406, -0.717980, -0.251620, 0.177511, 0.158120, -0.503299}; double delt=res/Wid; double delt0=df*delt; beta=zt[3]*beta+zt[4]*delt0*alf; alf=(zt[1]+zt[2]*delt*delt)*alf; double beta_p=beta/p; double feses=f+zt[5]*alf*beta/p /(2*M_PI)*Wid, yeses=y+zt[6]*alf*alf/p+zt[7]*log(1+beta_p*beta_p), pheses=ph+zt[8]*alf*alf*beta/p+zt[9]*atan(beta_p); //*/ f=feses/Wid, a=exp(yeses), ph=pheses, fslope=2*beta/2/M_PI, aesp=alf; }//TFAS05 /* function TFAS05_enh: the Abe-Smith method 2005 enhanced by LSE amplitude and phase estimation In: data[Wid]: waveform data w[Wid]: window function res: resolution of frequency for QIFFT Out: f, a, ph: frequency, amplitude and phase angle estimates aesp, fslope: estimates of log amplitude and frequency derivatives No return value. */ void TFAS05_enh(double& f, double& t, double& a, double& ph, double& aesp, double& fslope, int Wid, double* data, double* w, double res) { TFAS05(f, t, a, ph, aesp, fslope, Wid, data, w, res); double xr=0, xi=0, p, win2=0; for (int n=0; n<=Wid; n++) { double ni=n-Wid/2, tmp=data[n]*w[n]*w[n];//*exp(-aesp*(n-Wid/2)); if (IsInfinite(tmp)) continue; p=-2*M_PI*(f+0.5*fslope*ni)*ni; xr+=tmp*cos(p); xi+=tmp*sin(p); win2+=w[n]*w[n]; } a=sqrt(xr*xr+xi*xi)/win2; ph=(xr==0 && xi==0)?0:atan2(xi, xr); }//TFAS05_enh //version without returning aesp and fslope void TFAS05_enh(double& f, double& t, double& a, double& ph, int Wid, double* data, double* w, double res) { double aesp, fslope; TFAS05_enh(f, t, a, ph, aesp, fslope, Wid, data, w, res); }//TFAS05_enh //--------------------------------------------------------------------------- /* function DerivativeLSv_AmpPh: estimate the constant-term in the local derivative method. This is used by the local derivative algorithm, whose implementation is found in the header file as templates. In: sv0: inner product <s, v0>, where s is the sinusoid being estimated. integr_h[M][Wid]: M vectors containing samples of the integral of basis functions h[M]. v0[M]: a test function lmd[M]: coefficients to h[M] Returns coefficient of integr_h[0]=1. */ cdouble DerivativeLSv_AmpPh(int Wid, int M, double** integr_h, cdouble* lmd, cdouble* v0, cdouble sv0) { cdouble e0=0; for (int n=0; n<Wid; n++) { cdouble expo=0; for (int m=1; m<=M; m++) expo+=lmd[m]*integr_h[m][n]; e0+=exp(expo)**v0[n]; } return log(sv0/e0); }//DerivativeLSv_AmpPh //--------------------------------------------------------------------------- /* Piecewise derivative algorithm Further reading: Wen X. and M. Sandler, "Spline exponential approximation of time-varying sinusoids," under review. */ /* function setv: computes I test functions v[I] by modulation u[I] to frequency f In: u[I+1][Wid], du[I+1][Wid]: base-band test functions and their derivatives f: carrier frequency Out: v[I][Wid], dv[I][Wid]: test functions and their derivatives No return value. */ void setv(int I, int Wid, cdouble** v, cdouble** dv, double f, cdouble** u, cdouble** du) { double fbin=floor(f*Wid+0.5)/Wid; double omg=fbin*2*M_PI; cdouble jomg=cdouble(0, omg); for (int c=0; c<Wid; c++) { double t=c; cdouble rot=polar(1.0, omg*t); for (int i=0; i<I-1; i++) v[i][c]=u[i][c]*rot; for (int i=0; i<I-1; i++) dv[i][c]=du[i][c]*rot+jomg*v[i][c]; //Here it is assumed that elements of u[] are modulated at 0, 1, -1, 2, -2, 3, -3, 4, ...; //if f is under fbin then the closest ones are in order 0, -1, 1, -2, 3, -3, 3, .... This //makes a difference to the whole of v[] only if I is even. if (f>=fbin || I%2==1){v[I-1][c]=u[I-1][c]*rot; dv[I-1][c]=du[I-1][c]*rot+jomg*v[I-1][c];} else{v[I-1][c]=u[I][c]*rot; dv[I-1][c]=du[I][c]*rot+jomg*v[I-1][c];} } }//setv /* function setvhalf: computes I half-size test functions v[I] by modulation u[I] to frequency f. In: u[I][hWid*2], du[I][Wid*2]: base-band test functions and their derivatives f: carrier frequency Out: v[I][hWid], dv[hWid]: half-size test functions and their derivatives No return value. */void setvhalf(int I, int hWid, cdouble** v, cdouble** dv, double f, cdouble** u, cdouble** du) { double fbin=floor(f*hWid)/hWid; double omg=fbin*2*M_PI; cdouble jomg=cdouble(0, omg); for (int c=0; c<hWid; c++) { double t=c; cdouble rot=polar(1.0, omg*t); for (int i=0; i<I; i++) v[i][c]=u[i][c*2]*rot; for (int i=0; i<I; i++) dv[i][c]=rot*du[i][c*2]*cdouble(2.0)+jomg*v[i][c]; } }//setvhalf //#define ERROR_CHECK /* function DerivativePiecewise: Piecewise derivative algorithm. In this implementation of the piecewise method the test functions v are constructed from I "basic" (single-frame) test functions, each covering the same period of 2T, by shifting these I functions by steps of T. A total number of (L-1)I test functions are used. In: s[LT+1]: waveform data ds[LT+1]: derivative of s[LT], used only if ERROR_CHECK is defined. L, T: number and length of pieces. N: number of independent coefficients h[M][T]: piecewise basis functions A[L][M][N]: L matrices that map independent coefficients onto component coefficients over the L pieces u[I][2T}, du[I][2T]: base-band test functions f[L+1]: reference frequencies at 0, T, ..., LT, only f[1]...f[L-1] are used endmode: set to 1 or 3 to apply half-size testing over [0, T], to 2 or 3 to apply over [LT-T, LT] Out: aita[N]: independent coefficients No return value. */ void DerivativePiecewise(int N, cdouble* aita, int L, double* f, int T, cdouble* s, double*** A, int M, double** h, int I, cdouble** u, cdouble** du, int endmode, cdouble* ds) { MList* mlist=new MList; int L_1=(endmode==0)?(L-1):((endmode==3)?(L+1):L); cdouble** Allocate2L(cdouble, L_1, I, sv, mlist); cdouble** Allocate2(cdouble, I, T*2, v); cdouble** Allocate2(cdouble, I, T*2, dv); //compute <sr, v> cdouble*** Allocate3L(cdouble, L_1, I, N, srv, mlist); cdouble** Allocate2L(cdouble, I, M, shv1, mlist); cdouble** Allocate2L(cdouble, I, M, shv2, mlist); #ifdef ERROR_CHECK cdouble dsv1[128], dsv2[128]; #endif for (int l=0; l<L-1; l++) { //v from u given f[l] double fbin=floor(f[l+1]*T*2)/(T*2.0); double omg=fbin*2*M_PI; cdouble jomg=cdouble(0, omg); for (int c=0; c<T*2; c++) { double t=c-T; cdouble rot=polar(1.0, omg*t); for (int i=0; i<I; i++) v[i][c]=u[i][c]*rot; for (int i=0; i<I; i++) dv[i][c]=du[i][c]*rot+jomg*v[i][c]; } //compute -<s, v'> over the lth frame cdouble* ls=&s[l*T]; for (int i=0; i<I; i++) sv[l][i]=-Inner(2*T, ls, dv[i]); //compute <sr, v> over the lth frame cdouble *ls1=&s[l*T], *ls2=&s[l*T+T]; for (int i=0; i<I; i++) for (int m=0; m<M; m++) shv1[i][m]=Inner(T, ls1, h[m], v[i]), shv2[i][m]=Inner(T, ls2, h[m], &v[i][T]); //memset(srv[l][0], 0, sizeof(cdouble)*I*N); MultiplyXY(I, M, N, srv[l], shv1, A[l]); MultiAddXY(I, M, N, srv[l], shv2, A[l+1]); #ifdef ERROR_CHECK //error check: <s', v>=-<s, v'> if (ds) { cdouble* lds=&ds[l*T]; for (int i=0; i<I && l*I+1<36; i++) { cdouble lsv=Inner(2*T, lds, v[i]); //compute <s', v[i]> //cdouble* ls=&s[l*T]; //cdouble lsv2=Inner(2*T, ls, dv[i]); dsv1[l*I+i]=lsv-sv[l][i]; //i.e. <s', v[i]>=-<s, v[i]'>+dsv1[lI+i] } //error check: srv[l]*pq=<s',v> for (int i=0; i<I && l*I+i<36; i++) { cdouble lsv=0; for (int n=0; n<N; n++) lsv+=srv[l][i][n]*aita[n]; dsv2[l*I+i]=lsv-sv[l][i]-dsv1[l*I+i]; } } #endif } L_1=L-1; if (endmode==1 || endmode==3) { //v from u given f[l] int hT=T/2; double fbin=floor((f[0]+f[1])*hT)/T; double omg=fbin*2*M_PI; cdouble jomg=cdouble(0, omg); for (int c=0; c<T; c++) { double t=c-hT; cdouble rot=polar(1.0, omg*t); for (int i=0; i<I; i++) v[i][c]=u[i][c*2]*rot; for (int i=0; i<I; i++) dv[i][c]=rot*du[i][c*2]*cdouble(2.0)+jomg*v[i][c]; } //compute -<s, v'> over the lth frame cdouble* ls=&s[0]; for (int i=0; i<I; i++) sv[L_1][i]=-Inner(T, ls, dv[i]); //compute <sr, v> over the lth frame for (int i=0; i<I; i++) for (int m=0; m<M; m++) shv1[i][m]=Inner(T, ls, h[m], v[i]); //memset(srv[L_1][0], 0, sizeof(cdouble)*I*N); MultiplyXY(I, M, N, srv[L_1], shv1, A[0]); #ifdef ERROR_CHECK //error check: <s', v>=-<s, v'> if (ds) { cdouble* lds=&ds[0]; for (int i=0; i<I && L_1*I+1<36; i++) { cdouble lsv=Inner(T, lds, v[i]); //compute <s', v[i]> //cdouble* ls=&s[l*T]; //cdouble lsv2=Inner(2*T, ls, dv[i]); dsv1[L_1*I+i]=lsv-sv[L_1][i]; //i.e. <s', v[i]>=-<s, v[i]'>+dsv1[lI+i] } //error check: srv[l]*pq=<s',v> for (int i=0; i<I && L_1*I+i<36; i++) { cdouble lsv=0; for (int n=0; n<N; n++) lsv+=srv[L_1][i][n]*aita[n]; dsv2[L_1*I+i]=lsv-sv[L_1][i]-dsv1[L_1*I+i]; } } #endif L_1++; } if (endmode==2 || endmode==3) { //v from u given f[l] int hT=T/2; double fbin=floor((f[L-1]+f[L])*hT)/T; double omg=fbin*2*M_PI; cdouble jomg=cdouble(0, omg); for (int c=0; c<T; c++) { double t=c-hT; cdouble rot=polar(1.0, omg*t); for (int i=0; i<I; i++) v[i][c]=u[i][c*2]*rot; for (int i=0; i<I; i++) dv[i][c]=cdouble(2.0)*du[i][c*2]*rot+jomg*v[i][c]; } //compute -<s, v'> over the lth frame cdouble* ls=&s[(L-1)*T]; for (int i=0; i<I; i++) sv[L_1][i]=-Inner(T, ls, dv[i]); //compute <sr, v> over the lth frame for (int i=0; i<I; i++) for (int m=0; m<M; m++) shv1[i][m]=Inner(T, ls, h[m], v[i]); //memset(srv[L_1][0], 0, sizeof(cdouble)*I*N); MultiplyXY(I, M, N, srv[L_1], shv1, A[L-1]); #ifdef ERROR_CHECK //error check: <s', v>=-<s, v'> if (ds) { cdouble* lds=&ds[(L-1)*T]; for (int i=0; i<I && L_1*I+1<36; i++) { cdouble lsv=Inner(T, lds, v[i]); //compute <s', v[i]> //cdouble* ls=&s[l*T]; //cdouble lsv2=Inner(2*T, ls, dv[i]); dsv1[L_1*I+i]=lsv-sv[L_1][i]; //i.e. <s', v[i]>=-<s, v[i]'>+dsv1[lI+i] } //error check: srv[l]*pq=<s',v> for (int i=0; i<I && L_1*I+i<36; i++) { cdouble lsv=0; for (int n=0; n<N; n++) lsv+=srv[L_1][i][n]*aita[n]; dsv2[L_1*I+i]=lsv-sv[L_1][i]-dsv1[L_1*I+i]; } } #endif L_1++; } if (L_1*2*I==2*N) GECP(N, aita, srv[0], sv[0]); else LSLinear(L_1*I, N, aita, srv[0], sv[0]); delete mlist; }//DerivativePiecewise /* function DerivativePiecewise2: Piecewise derivative algorithm in which the real and imaginary parts of the exponent are modelled separately. In this implementation of the piecewise method the test functions v are constructed from I "basic" (single-frame) test functions, each covering the same period of 2T, by shifting these I functions by steps of T. A total number of (L-1)I test functions are used. In: s[LT+1]: waveform data ds[LT+1]: derivative of s[LT], used only if ERROR_CHECK is defined. L, T: number and length of pieces. N: number of independent coefficients h[M][T]: piecewise basis functions A[L][M][Np]: L matrices that do coefficient mapping (real part) over the L pieces B[L][M][Nq]: L matrices that do coefficient mapping (imaginary part) over the L pieces u[I][2T}, du[I][2T]: base-band test functions f[L+1]: reference frequencies at 0, T, ..., LT, only f[1]...f[L-1] are used endmode: set to 1 or 3 to apply half-size testing over [0, T], to 2 or 3 to apply over [LT-T, LT] Out: p[Np], q[Nq]: independent coefficients No return value. */ void DerivativePiecewise2(int Np, double* p, int Nq, double* q, int L, double* f, int T, cdouble* s, double*** A, double*** B, int M, double** h, int I, cdouble** u, cdouble** du, int endmode, cdouble* ds) { MList* mlist=new MList; int L_1=(endmode==0)?(L-1):((endmode==3)?(L+1):L); cdouble** Allocate2L(cdouble, L_1, I, sv, mlist); cdouble** Allocate2(cdouble, I, T*2, v); cdouble** Allocate2(cdouble, I, T*2, dv); //compute <sr, v> cdouble*** Allocate3L(cdouble, L_1, I, Np, srav, mlist); cdouble*** srbv; if (Np==Nq && B==A) srbv=srav; else {Allocate3L(cdouble, L_1, I, Nq, srbv, mlist);} //same model for amplitude and phase cdouble** Allocate2L(cdouble, I, M, shv1, mlist); cdouble** Allocate2L(cdouble, I, M, shv2, mlist); for (int l=0; l<L-1; l++) { //v from u given f[l] double fbin=floor(f[l+1]*T*2)/(T*2.0); double omg=fbin*2*M_PI; cdouble jomg=cdouble(0, omg); for (int c=0; c<T*2; c++) { double t=c-T; cdouble rot=polar(1.0, omg*t); for (int i=0; i<I; i++) v[i][c]=u[i][c]*rot; for (int i=0; i<I; i++) dv[i][c]=du[i][c]*rot+jomg*v[i][c]; } //compute -<s, v'> over the lth frame cdouble* ls=&s[l*T]; for (int i=0; i<I; i++) sv[l][i]=-Inner(2*T, ls, dv[i]); //compute <sr, v> over the lth frame cdouble *ls1=&s[l*T], *ls2=&s[l*T+T]; for (int i=0; i<I; i++) for (int m=0; m<M; m++) shv1[i][m]=Inner(T, ls1, h[m], v[i]), shv2[i][m]=Inner(T, ls2, h[m], &v[i][T]); memset(srav[l][0], 0, sizeof(cdouble)*I*Np); MultiplyXY(I, M, Np, srav[l], shv1, A[l]); MultiAddXY(I, M, Np, srav[l], shv2, A[l+1]); if (srbv!=srav) //so that either B!=A or Np!=Nq { //memset(srbv[l][0], 0, sizeof(cdouble)*I*Nq); MultiplyXY(I, M, Nq, srbv[l], shv1, B[l]); MultiAddXY(I, M, Nq, srbv[l], shv2, B[l+1]); } } L_1=L-1; if (endmode==1 || endmode==3) { //v from u given f[l] int hT=T/2; double fbin=floor((f[0]+f[1])*hT)/T; double omg=fbin*2*M_PI; cdouble jomg=cdouble(0, omg); for (int c=0; c<T; c++) { double t=c-hT; cdouble rot=polar(1.0, omg*t); for (int i=0; i<I; i++) v[i][c]=u[i][c*2]*rot; for (int i=0; i<I; i++) dv[i][c]=rot*du[i][c*2]*cdouble(2.0)+jomg*v[i][c]; } //compute -<s, v'> over the lth frame cdouble* ls=&s[0]; for (int i=0; i<I; i++) sv[L_1][i]=-Inner(T, ls, dv[i]); //compute <sr, v> over the lth frame for (int i=0; i<I; i++) for (int m=0; m<M; m++) shv1[i][m]=Inner(T, ls, h[m], v[i]); //memset(srav[L_1][0], 0, sizeof(cdouble)*I*Np); MultiplyXY(I, M, Np, srav[L_1], shv1, A[0]); if (srbv!=srav) {memset(srbv[L_1][0], 0, sizeof(cdouble)*I*Nq); MultiplyXY(I, M, Nq, srbv[L_1], shv1, B[0]);} L_1++; } if (endmode==2 || endmode==3) { //v from u given f[l] int hT=T/2; double fbin=floor((f[L-1]+f[L])*hT)/T; double omg=fbin*2*M_PI; cdouble jomg=cdouble(0, omg); for (int c=0; c<T; c++) { double t=c-hT; cdouble rot=polar(1.0, omg*t); for (int i=0; i<I; i++) v[i][c]=u[i][c*2]*rot; for (int i=0; i<I; i++) dv[i][c]=cdouble(2.0)*du[i][c*2]*rot+jomg*v[i][c]; } //compute -<s, v'> over the lth frame cdouble* ls=&s[(L-1)*T]; for (int i=0; i<I; i++) sv[L_1][i]=-Inner(T, ls, dv[i]); //compute <sr, v> over the lth frame for (int i=0; i<I; i++) for (int m=0; m<M; m++) shv1[i][m]=Inner(T, ls, h[m], v[i]); memset(srav[L_1][0], 0, sizeof(cdouble)*I*Np); MultiplyXY(I, M, Np, srav[L_1], shv1, A[L-1]); if (srbv!=srav) { //memset(srbv[L_1][0], 0, sizeof(cdouble)*I*Nq); MultiplyXY(I, M, Nq, srbv[L_1], shv1, B[L-1]); } L_1++; } //real implementation of <sr,v>aita=<s',v> double** Allocate2L(double, L_1*I*2, Np+Nq, AM, mlist); for (int l=0; l<L_1; l++) for (int i=0; i<I; i++) { int li=l*I+i, li_H=li+L_1*I; for (int n=0; n<Np; n++) { AM[li][n]=srav[l][i][n].x; AM[li_H][n]=srav[l][i][n].y; } for (int n=0; n<Nq; n++) { AM[li][Np+n]=-srbv[l][i][n].y; AM[li_H][Np+n]=srbv[l][i][n].x; } } //least-square solution of (srv)(aita)=(sv) double* pq=new double[Np+Nq]; mlist->Add(pq, 1); double* b=new double[2*L_1*I]; for (int i=0; i<L_1*I; i++) b[i]=sv[0][i].x, b[i+L_1*I]=sv[0][i].y; if (L_1*2*I==Np+Nq) GECP(Np+Nq, pq, AM, b); else LSLinear(2*L_1*I, Np+Nq, pq, AM, b); memcpy(p, pq, sizeof(double)*Np); memcpy(q, &pq[Np], sizeof(double)*Nq); delete mlist; }//DerivativePiecewise2 /* Error check: test that ds[LT] equals s[LT] times reconstructed R'. Notice that DA is D time A where D is a pre-emphasis because p[Np] applies to log amplitude rather than its derivative. */ double testds_pqA(int Np, double* p, int Nq, double* q, int L, int T, cdouble* s, cdouble* ds, int M, double** h, double** dh, double*** DA, double*** B, cdouble* errds=0) { double err=0, ene=0, *lamdax=new double[M*2], *lamday=&lamdax[M]; for (int l=0; l<L; l++) { MultiplyXy(M, Np, lamdax, DA[l], p); MultiplyXy(M, Nq, lamday, B[l], q); for (int t=0; t<T; t++) { double drtx=0; for (int m=0; m<M; m++) drtx+=lamdax[m]*h[m][t]; double drty=0; for (int m=0; m<M; m++) drty+=lamday[m]*h[m][t]; cdouble drt=cdouble(drtx, drty); cdouble eds=ds[l*T+t]-s[l*T+t]*drt; err+=~eds; ene+=~ds[l*T+t]; if (errds) errds[l*T+t]=eds; } } delete[] lamdax; return err/ene; }//testds_pqA /* Error check: dsv1[I] tests that <s', v[I]> equals -<s, v[I]'>, dsv2[I] tests that <sr, v[I]>*pq= <s',v[I]> */ void testdsv(cdouble* dsv1, cdouble* dsv2, int Np, double* p, int Nq, double* q, int TT, cdouble* dsl, int I, cdouble** vl, cdouble* svl, cdouble** sravl, cdouble** srbvl) { for (int i=0; i<I; i++) { cdouble lsv=Inner(TT, dsl, vl[i]); //compute <s', v[i]> //cdouble* ls=&s[l*T]; dsv1[i]=lsv-svl[i]; //i.e. <s', v[i]>=-<s, v[i]'>+dsv1[lI+i] //sv[l][i]=lsv; } //error check: srv[l]*pq=<s',v> for (int i=0; i<I; i++) { cdouble lsv=0; for (int n=0; n<Np; n++) lsv+=sravl[i][n]*p[n]; for (int n=0; n<Nq; n++) lsv+=srbvl[i][n]*cdouble(0, q[n]); dsv2[i]=lsv-svl[i]-dsv1[i]; } }//testdsv /* Error check: tests A[MN]x[N1]=b[N1], returns square error */ double testlinearsystem(int M, int N, double** A, double* x, double* b) { double err=0; for (int m=0; m<M; m++) { double errli=Inner(N, A[m], x)-b[m]; err+=errli*errli; } return err; }//testlinearsystem /* Error check: test the total square norm of <s, v> */ double testsv(int L, double* f, int T, cdouble* s, int I, cdouble** u, cdouble** du, int endmode) { cdouble** Allocate2(cdouble, I, T*2, v); cdouble** Allocate2(cdouble, I, T*2, dv); double ene=0; for (int l=0; l<L-1; l++) { //v from u given f[l] setv(I, T*2, v, dv, f[l+1], u, du); //compute -<s, v'> over the lth frame cdouble* ls=&s[l*T]; for (int i=0; i<I; i++) { cdouble d=Inner(2*T, ls, v[i]); ene+=~d; } } if (endmode==1 || endmode==3) { //v from u given f[l] setvhalf(I, T, v, dv, (f[0]+f[1])/2, u, du); cdouble* ls=&s[0]; for (int i=0; i<I; i++) ene+=~Inner(T, ls, v[i]); } if (endmode==2 || endmode==3) { //v from u given f[l] setvhalf(I, T, v, dv, (f[L-1]+f[L])/2, u, du); cdouble* ls=&s[(L-1)*T]; for (int i=0; i<I; i++) ene+=~Inner(T, ls, v[i]); } DeAlloc2(v); DeAlloc2(dv); return ene; }//testsv /* function DerivativePiecewise3: Piecewise derivative algorithm in which the log amplitude and frequeny are modeled separately as piecewise functions. In this implementation of the piecewise method the test functions v are constructed from I "basic" (single-frame) test functions, each covering the same period of 2T, by shifting these I functions by steps of T. A total number of (L-1)I test functions are used. In: s[LT+1]: waveform data ds[LT+1]: derivative of s[LT], used only if ERROR_CHECK is defined. L, T: number and length of pieces. N: number of independent coefficients h[M][T]: piecewise basis functions dh[M][T]: derivative of h[M][T], used only if ERROR_CHECK is defined. DA[L][M][Np]: L matrices that do coefficient mapping (real part) over the L pieces B[L][M][Nq]: L matrices that do coefficient mapping (imaginary part) over the L pieces u[I][2T}, du[I][2T]: base-band test functions f[L+1]: reference frequencies at 0, T, ..., LT, only f[1]...f[L-1] are used endmode: set to 1 or 3 to apply half-size testing over [0, T], to 2 or 3 to apply over [LT-T, LT] Out: p[Np], q[Nq]: independent coefficients No return value. */ void DerivativePiecewise3(int Np, double* p, int Nq, double* q, int L, double* f, int T, cdouble* s, double*** DA, double*** B, int M, double** h, int I, cdouble** u, cdouble** du, int endmode, cdouble* ds, double** dh) { MList* mlist=new MList; int L_1=(endmode==0)?(L-1):((endmode==3)?(L+1):L); cdouble** Allocate2L(cdouble, L_1, I, sv, mlist); cdouble** Allocate2L(cdouble, I, T*2, v, mlist); cdouble** Allocate2L(cdouble, I, T*2, dv, mlist); //compute <sr, v> cdouble*** Allocate3L(cdouble, L_1, I, Np, srav, mlist); cdouble*** srbv; if (Np==Nq && B==DA) srbv=srav; else {Allocate3L(cdouble, L_1, I, Nq, srbv, mlist);} //same model for amplitude and phase cdouble** Allocate2L(cdouble, I, M, shv1, mlist); cdouble** Allocate2L(cdouble, I, M, shv2, mlist); #ifdef ERROR_CHECK cdouble dsv1in[128], dsv2in[128]; #endif for (int l=0; l<L-1; l++) { //v from u given f[l] setv(I, T*2, v, dv, f[l+1], u, du); //compute -<s, v'> over the lth frame cdouble* ls=&s[l*T]; for (int i=0; i<I; i++) sv[l][i]=-Inner(2*T, ls, dv[i]); //compute <sr, v> over the lth frame cdouble *ls1=&s[l*T], *ls2=&s[l*T+T]; for (int i=0; i<I; i++) for (int m=0; m<M; m++) shv1[i][m]=Inner(T, ls1, h[m], v[i]), shv2[i][m]=Inner(T, ls2, h[m], &v[i][T]); memset(srav[l][0], 0, sizeof(cdouble)*I*Np); MultiplyXY(I, M, Np, srav[l], shv1, DA[l]); MultiAddXY(I, M, Np, srav[l], shv2, DA[l+1]); if (srbv!=srav) //so that either B!=A or Np!=Nq { MultiplyXY(I, M, Nq, srbv[l], shv1, B[l]); MultiAddXY(I, M, Nq, srbv[l], shv2, B[l+1]); } #ifdef ERROR_CHECK //error check: <s', v>=-<s, v'> and srv[l]*pq=<s',v> if (ds) testdsv(&dsv1in[l*I], &dsv2in[l*I], Np, p, Nq, q, T*2, &ds[l*T], I, v, sv[l], srav[l], srbv[l]); #endif } L_1=L-1; if (endmode==1 || endmode==3) { //v from u given f[l] setvhalf(I, T, v, dv, (f[0]+f[1])/2, u, du); //compute -<s, v'> over the lth frame cdouble* ls=&s[0]; for (int i=0; i<I; i++) sv[L_1][i]=-Inner(T, ls, dv[i]); //compute <sr, v> over the lth frame for (int i=0; i<I; i++) for (int m=0; m<M; m++) shv1[i][m]=Inner(T, ls, h[m], v[i]); //memset(srav[L_1][0], 0, sizeof(cdouble)*I*Np); MultiplyXY(I, M, Np, srav[L_1], shv1, DA[0]); if (srbv!=srav) {memset(srbv[L_1][0], 0, sizeof(cdouble)*I*Nq); MultiplyXY(I, M, Nq, srbv[L_1], shv1, B[0]);} #ifdef ERROR_CHECK //error check: <s', v>=-<s, v'> and srv[l]*pq=<s',v> if (ds) testdsv(&dsv1in[L_1*I], &dsv2in[L_1*I], Np, p, Nq, q, T, &ds[0], I, v, sv[L_1], srav[L_1], srbv[L_1]); #endif L_1++; } if (endmode==2 || endmode==3) { //v from u given f[l] setvhalf(I, T, v, dv, (f[L-1]+f[L])/2, u, du); //compute -<s, v'> over the lth frame cdouble* ls=&s[(L-1)*T]; for (int i=0; i<I; i++) sv[L_1][i]=-Inner(T, ls, dv[i]); //compute <sr, v> over the lth frame for (int i=0; i<I; i++) for (int m=0; m<M; m++) shv1[i][m]=Inner(T, ls, h[m], v[i]); memset(srav[L_1][0], 0, sizeof(cdouble)*I*Np); MultiplyXY(I, M, Np, srav[L_1], shv1, DA[L-1]); if (srbv!=srav) MultiplyXY(I, M, Nq, srbv[L_1], shv1, B[L-1]); #ifdef ERROR_CHECK //error check: <s', v>=-<s, v'> and srv[l]*pq=<s',v> if (ds) testdsv(&dsv1in[L_1*I], &dsv2in[L_1*I], Np, p, Nq, q, T, &ds[(L-1)*T], I, v, sv[L_1], srav[L_1], srbv[L_1]); #endif L_1++; } //real implementation of <sr,v>aita=<s',v> double** Allocate2L(double, L_1*I*2, Np+Nq, AM, mlist); for (int l=0; l<L_1; l++) for (int i=0; i<I; i++) { int li=l*I+i, li_H=li+L_1*I; for (int n=0; n<Np; n++) { AM[li][n]=srav[l][i][n].x; AM[li_H][n]=srav[l][i][n].y; } for (int n=0; n<Nq; n++) { AM[li][Np+n]=-srbv[l][i][n].y; AM[li_H][Np+n]=srbv[l][i][n].x; } } //least-square solution of (srv)(aita)=(sv) double* pq=new double[Np+Nq]; mlist->Add(pq, 1); double* b=new double[2*L_1*I]; for (int i=0; i<L_1*I; i++) b[i]=sv[0][i].x, b[i+L_1*I]=sv[0][i].y; mlist->Add(b, 1); #ifdef ERROR_CHECK //tests that AM is invariant to a constant shift of p double errAM=0, errAM2=0, err1, err2; for (int l=0; l<L_1*I; l++){double errli=0; for (int n=0; n<Np; n++) errli+=AM[l][n]; errAM+=errli*errli; errli=0; for (int n=0; n<Np; n+=2) errli+=AM[l][n]; errAM2+=errli*errli;} //test square error of the input pq if (ds) { memcpy(pq, p, sizeof(double)*Np); memcpy(&pq[Np], q, sizeof(double)*Nq); err1=testlinearsystem(L_1*I*2, Np+Nq, AM, pq, b); } //test error of s'-sR where R is synthesized from the input pq double errdsin, errdsvin; cdouble* edsin; if (ds && dh) { edsin=new cdouble[L*T]; mlist->Add(edsin, 1); errdsin=testds_pqA(Np, p, Nq, q, L, T, s, ds, M, h, dh, DA, B, edsin); errdsvin=testsv(L, f, T, edsin, I, u, du, endmode); } #endif Alloc2L(L_1*I*2, Np+Nq-1, Am, mlist); for (int l=0; l<L_1*I*2; l++) memcpy(Am[l], &AM[l][1], sizeof(double)*(Np+Nq-1)); pq[0]=0; //if (L_1*2*I==Np+Nq) GECP(Np+Nq, pq, AM, b); //else LSLinear(2*L_1*I, Np+Nq, pq, AM, b); if (L_1*2*I==Np+Nq-1) GECP(Np+Nq-1, &pq[1], Am, b); else LSLinear(2*L_1*I, Np+Nq-1, &pq[1], Am, b); #ifdef ERROR_CHECK //test square error of output pq if (ds) err2=testlinearsystem(L_1*I*2, Np+Nq, AM, pq, b); //test error of s'-sR of the output pq double errdsout, errdsvout; cdouble* edsout; if (ds && dh) { edsout=new cdouble[L*T]; mlist->Add(edsout, 1); errdsout=testds_pqA(Np, pq, Nq, &pq[Np], L, T, s, ds, M, h, dh, DA, B, edsout); errdsvout=testsv(L, f, T, edsout, I, u, du, endmode); } #endif memcpy(p, pq, sizeof(double)*Np); memcpy(q, &pq[Np], sizeof(double)*Nq); delete mlist; }//DerivativePiecewise3 //initialization routines for the piecewise derivative method /* function seth: set h[M] to a series of power functions. In: M, T. Out: h[M][T], where h[m] is power function of order m. No return value. h is allocated anew and must be freed by caller. */ void seth(int M, int T, double**& h, MList* mlist) { if (M<=0){h=0; return;} Allocate2L(double, M, T, h, mlist); double* hm=h[0]; for (int t=0; t<T; t++) hm[t]=1; for (int m=1; m<M; m++) { hm=h[m]; for (int t=0; t<T; t++) hm[t]=pow(t*1.0, m); } }//seth /* function setdh: set dh[M] to the derivative of a series of power functions. In: M, T. Out: dh[M][T], where dh[m] is derivative of the power function of order m. No return value. dh is allocated anew and must be freed by caller. */ void setdh(int M, int T, double**& dh, MList* mlist) { if (M<=0){dh=0; return;} Allocate2L(double, M, T, dh, mlist); double* dhm=dh[0]; memset(dhm, 0, sizeof(double)*T); if (M>1){dhm=dh[1]; for (int t=0; t<T; t++) dhm[t]=1;} for (int m=2; m<M; m++) { dhm=dh[m]; for (int t=0; t<T; t++) dhm[t]=m*pow(t*1.0, m-1); } }//setdh /* function setdih: set dih[M] to the difference of the integral of a series of power functions. In: M, I Out: dih[M][I], where the accumulation of dih[m] is the integral of the power function of order m. No return value. dih is allocated anew and must be freed by caller. */ void setdih(int M, int T, double**& dih, MList* mlist) { if (M<=0){dih=0; return;} Allocate2L(double, M, T, dih, mlist); double* dihm=dih[0]; for (int t=0; t<T; t++) dihm[t]=1; for (int m=1; m<M; m++) { dihm=dih[m]; for (int t=0; t<T; t++) dihm[t]=(pow(t+1.0, m+1)-pow(t*1.0, m+1))/(m+1); } }//setdih /* function sshLinear: sets M and h[M] for the linear spline model In: T Out: M=2, h[2][T] filled out for linear spline model. No return value. h is allocated anew and must be freed by caller. */ void sshLinear(int T, int& M, double** &h, MList* mlist) { M=2; Allocate2L(double, M, T, h, mlist); for (int t=0; t<T; t++) h[0][t]=1, h[1][t]=t; }//sshLinear /* function sdihLinear: sets dih[M] for the linear spline model. For testing only. In: T Out: dih[2][T] filled out for linear spline model. No return value. dih is allocated anew and must be freed by caller. */ void sdihLinear(int T, double**& dih, MList* mlist) { Allocate2L(double, 2, T, dih, mlist); for (int t=0; t<T; t++) dih[0][t]=1, dih[1][t]=t+0.5; }//sdihLinear /* function sshCubic: sets M and h[M] for cubic spline models. In: T Out: M=4 and h[M] filled out for cubic spline models, including cubic and cubic-Hermite. No return value. h is allocated anew and must be freed by caller. */ void sshCubic(int T, int& M, double** &h, MList* mlist) { M=4; Allocate2L(double, M, T, h, mlist); for (int t=0; t<T; t++) h[3][t]=t*t*t, h[2][t]=t*t, h[1][t]=t, h[0][t]=1; }//sshCubic /* function sdihCubic: sets dih[M] for cubic spline models. In: T Out: dih[4] filled out for cubic spline models. No return value. dih is allocated anew and must be freed by caller. */ void sdihCubic(int T, double** &dih, MList* mlist) { Allocate2L(double, 4, T, dih, mlist); for (int t=0; t<T; t++) { dih[3][t]=t*(t*(t+1.5)+1)+0.25, dih[2][t]=t*(t+1)+1.0/3, dih[1][t]=t+0.5, dih[0][t]=1; } }//sdihCubic*/ /* function ssALinearSpline: sets N and A[L] for the linear spline model In: L, M, T Out: N=L+1, A[L][M][N] filled out for the linear spline model No return value. A is created anew and bust be freed by caller. */ void ssALinearSpline(int L, int T, int M, int& N, double*** &A, MList* mlist, int mode) { N=L+1; Allocate3L(double, L, M, N, A, mlist); memset(A[0][0], 0, sizeof(double)*L*M*N); double iT=1.0/T; for (int l=0; l<L; l++) A[l][0][l]=1, A[l][1][l]=-iT, A[l][1][l+1]=iT; }//ssALinearSpline /* function ssLinearSpline: sets M, N, h and A for the linear spline model In: L, M, T Out: N and h[][] and A[][][] filled out for the linear spline model No reutrn value. A and h are created anew and bust be freed by caller. */ void ssLinearSpline(int L, int T, int M, int &N, double** &h, double*** &A, MList* mlist, int mode) { seth(M, T, h, mlist); ssALinearSpline(L, T, M, N, A, mlist); }//ssLinearSpline /* function ssACubicHermite: sets N and A[L] for cubic Hermite spline model In: L, M, T Out: N=2(L+1), A[L][M][N] filled out for the cubic Hermite spline No return value. A is created anew and must be freed by caller. */ void ssACubicHermite(int L, int T, int M, int& N, double*** &A, MList* mlist, int mode) { N=2*(L+1); Allocate3L(double, L, M, N, A, mlist); memset(A[0][0], 0, sizeof(double)*L*M*N); double iT=1.0/T, iT2=iT*iT, iT3=iT2*iT; for (int l=0; l<L; l++) { A[l][3][2*l]=2*iT3; A[l][3][2*l+2]=-2*iT3; A[l][3][2*l+1]=A[l][3][2*l+3]=iT2; A[l][2][2*l]=-3*iT2; A[l][2][2*l+1]=-2*iT; A[l][2][2*l+2]=3*iT2; A[l][2][2*l+3]=-iT; A[l][1][2*l+1]=1; A[l][0][2*l]=1; } }//ssACubicHermite /* function ssLinearSpline: sets M, N, h and A for the cubic Hermite spline model In: L, M, T Out: N and h[][] and A[][][] filled out for the cubic Hermite spline model No reutrn value. A and h are created anew and bust be freed by caller. */ void ssCubicHermite(int L, int T, int M, int& N, double** &h, double*** &A, MList* mlist, int mode) { seth(M, T, h, mlist); ssACubicHermite(L, T, M, N, A, mlist); }//ssCubicHermite /* function ssACubicSpline: sets N and A[L] for cubic spline model In: L, M, T mode: boundary mode of cubic spline, 0=natural, 1=quadratic run-out, 2=cubic run-out Out: N=2(L+1), A[L][M][N] filled out for the cubic spline No return value. A is created anew and must be freed by caller. */ void ssACubicSpline(int L, int T, int M, int& N, double*** &A, MList* mlist, int mode) { N=L+1; Allocate3L(double, L, M, N, A, mlist); memset(A[0][0], 0, sizeof(double)*L*M*N); Alloc2(L+1, L+1, ML); memset(ML[0], 0, sizeof(double)*(L+1)*(L+1)); Alloc2(L+1, L+1, MR); memset(MR[0], 0, sizeof(double)*(L+1)*(L+1)); //fill in ML and MR. The only difference between various cubic splines are ML. double _6iT2=6.0/(T*T); ML[0][0]=ML[L][L]=1; for (int l=1; l<L; l++) ML[l][l-1]=ML[l][l+1]=1, ML[l][l]=4, MR[l][l-1]=MR[l][l+1]=_6iT2, MR[l][l]=-2*_6iT2; if (mode==0){} //no more coefficients are needed for natural cubic spline else if (mode==1) ML[0][1]=ML[L][L-1]=-1; //setting for quadratic run-out else if (mode==2) ML[0][1]=ML[L][L-1]=-2, ML[0][2]=ML[L][L-2]=1; //setting for cubic run-out GICP(L+1, ML); double** MM=MultiplyXY(L+1, ML, ML, MR); double iT=1.0/T; Alloc2(4, 2, M42); M42[3][0]=-1.0/6/T, M42[3][1]=1.0/6/T, M42[2][0]=0.5, M42[2][1]=M42[0][0]=M42[0][1]=0, M42[1][0]=-T/3.0, M42[1][1]=-T/6.0; for (int l=0; l<L; l++) { MultiplyXY(4, 2, N, A[l], M42, &MM[l]); A[l][1][l]-=iT; A[l][1][l+1]+=iT; A[l][0][l]+=1; } DeAlloc2(ML); DeAlloc2(MR); DeAlloc2(M42); }//ssACubicSpline /* function ssLinearSpline: sets M, N, h and A for the cubic spline model In: L, M, T Out: N and h[][] and A[][][] filled out for the cubic spline model No reutrn value. A and h are created anew and bust be freed by caller. */ void ssCubicSpline(int L, int T, int M, int& N, double** &h, double*** &A, MList* mlist, int mode) { seth(M, T, h, mlist); ssACubicSpline(L, T, M, N, A, mlist, mode); }//ssCubicSpline /* function setu: sets u[I+1] as base-band windowed Fourier atoms, whose frequencies come in the order of 0, 1, -1, 2, -2, 3, -3, 4, etc, in bins. In: I, Wid: number and size of atoms to generate. WinOrder: order (=vanishing moment) of window function to use (2=Hann, 4=Hann^2, etc.) Out: u[I+1][Wid], du[I+1]{Wid]: the I+1 atoms and their derivatives. No return value. u and du are created anew and must be freed by caller. */ void setu(int I, int Wid, cdouble**& u, cdouble**& du, int WinOrder, MList* mlist) { Allocate2L(cdouble, I+1, Wid, u, mlist); Allocate2L(cdouble, I+1, Wid, du, mlist); double** wins=CosineWindows(WinOrder, Wid, (double**)0, 2); double omg=2*M_PI/Wid; cdouble jomg=cdouble(0, omg); for (int t=0; t<Wid; t++) { u[0][t]=wins[0][t], du[0][t]=wins[1][t]; int li=1; for (int i=1; i<=I; i++) { cdouble rot=polar(1.0, li*omg*t); u[i][t]=u[0][t]*rot; du[i][t]=du[0][t]*rot+jomg*li*u[i][t]; li=-li; if (li>0) li++; } } DeAlloc2(wins); }//setu /* function DerivativePiecewiseI: wrapper for DerivativePiecewise(), doing the initialization ,etc. In: L, T: number and length of pieces s[LT]: waveform signal ds[LT]: derivative of s[LT], used only when ERROR_CHECK is defined. f[L+1]: reference frequencies at knots M: polynomial degree of piecewise approximation SpecifyA, ssmode: pointer to a function that fills A[L], and mode argument to call it WinOrder: order(=vanishing moment) of window used for constructing test functions I: number of test functions per frame. endmode: set to 1 or 3 to apply half-size frame over [0, T], to 2 or 3 to apply over [LT-T, LT] Out: aita[N]: independent coefficients, where N is specified by SpecifyA. No return vlue. */ void DerivativePiecewiseI(cdouble* aita, int L, double* f, int T, cdouble* s, int M, void (*SpecifyA)(int L, int T, int M, int &N, double*** &A, MList* mlist, int mode), int ssmode, int WinOrder, int I, int endmode, cdouble* ds) { MList* mlist=new MList; cdouble **u, **du; setu(I, 2*T, u, du, WinOrder, mlist); int N; double **h, ***A; seth(M, T, h, mlist); SpecifyA(L, T, M, N, A, mlist, ssmode); DerivativePiecewise(N, aita, L, f, T, s, A, M, h, I, u, du, endmode, ds); delete mlist; }//DerivativePiecewiseI /* function DerivativePiecewiseII: wrapper for DerivativePiecewise2(), doing the initialization ,etc. This models the derivative of log ampltiude and frequency as separate piecewise polynomials, the first specified by SpecifyA, the second by SpecifyB. In: L, T: number and length of pieces s[LT]: waveform signal ds[LT]: derivative of s[LT], used only when ERROR_CHECK is defined. f[L+1]: reference frequencies at knots M: polynomial degree of piecewise approximation SpecifyA, ssAmode: pointer to a function that fills A[L], and mode argument to call it SpecifyB, ssBmode: pointer to a function that fills B[L], and mode argument to call it WinOrder: order(=vanishing moment) of window used for constructing test functions I: number of test functions per frame. endmode: set to 1 or 3 to apply half-size frame over [0, T], to 2 or 3 to apply over [LT-T, LT] Out: p[Np], q[Nq]: independent coefficients, where Np and Nq are specified by SpecifyA and SpecifyB. No reutrn value. */ void DerivativePiecewiseII(double* p, double* q, int L, double* f, int T, cdouble* s, int M, void (*SpecifyA)(int L, int T, int M, int &N, double*** &A, MList* mlist, int mode), int ssAmode, void (*SpecifyB)(int L, int T, int M, int &N, double*** &B, MList* mlist, int mode), int ssBmode, int WinOrder, int I, int endmode, cdouble* ds) { MList* mlist=new MList; cdouble **u, **du; setu(I, 2*T, u, du, WinOrder, mlist); int Np, Nq; double **h, ***A, ***B; seth(M, T, h, mlist); SpecifyA(L, T, M, Np, A, mlist, ssAmode); SpecifyB(L, T, M, Nq, B, mlist, ssBmode); DerivativePiecewise2(Np, p, Nq, q, L, f, T, s, A, B, M, h, I, u, du, endmode, ds); delete mlist; }//DerivativePiecewiseII /* function DerivativePiecewiseIII: wrapper for DerivativePiecewise3(), doing the initialization ,etc. Notice that this time the log amplitude, rather than its derivative, is modeled as a piecewise polynomial specified by SpecifyA. In: L, T: number and length of pieces s[LT]: waveform signal ds[LT]: derivative of s[LT], used only when ERROR_CHECK is defined. f[L+1]: reference frequencies at knots M: polynomial degree of piecewise approximation SpecifyA, ssAmode: pointer to a function that fills A[L], and mode argument to call it SpecifyB, ssBmode: pointer to a function that fills B[L], and mode argument to call it WinOrder: order(=vanishing moment) of window used for constructing test functions I: number of test functions per frame. endmode: set to 1 or 3 to apply half-size frame over [0, T], to 2 or 3 to apply over [LT-T, LT] Out: p[Np], q[Nq]: independent coefficients, where Np and Nq are specified by SpecifyA and SpecifyB. No reutrn value. */ void DerivativePiecewiseIII(double* p, double* q, int L, double* f, int T, cdouble* s, int M, void (*SpecifyA)(int L, int T, int M, int &N, double*** &A, MList* mlist, int mode), int ssAmode, void (*SpecifyB)(int L, int T, int M, int &N, double*** &B, MList* mlist, int mode), int ssBmode, int WinOrder, int I, int endmode, cdouble* ds) { MList* mlist=new MList; int Np, Nq; double **h, ***A, ***B, **dh=0; cdouble **u, **du; setu(I, T*2, u, du, WinOrder, mlist); seth(M, T, h, mlist); if (ds) setdh(M, T, dh, mlist); SpecifyA(L, T, M, Np, A, mlist, ssAmode); SpecifyB(L, T, M, Nq, B, mlist, ssBmode); Alloc2L(M, M, DM, mlist); memset(DM[0], 0, sizeof(double)*M*M); for (int m=0; m<M-1; m++) DM[m][m+1]=m+1; double** DA=0; for (int l=0; l<L; l++) { DA=MultiplyXY(M, M, Np, DA, DM, A[l], mlist); Copy(M, Np, A[l], DA); } DerivativePiecewise3(Np, p, Nq, q, L, f, T, s, A, B, M, h, I, u, du, endmode, ds, dh); delete mlist; }//DerivativePiecewiseIII /* function AmpPhCorrectionExpA: model-preserving amplitude and phase correction in piecewise derivative method. In: aita[N]: inital independent coefficients L, T: number and size of pieces sre[LT]: waveform data h[M][T], dih[M][T]: piecewise basis functions and their difference-integrals A[L][M][N]: L coefficient mapping matrices SpecifyA: pointer to the function used for constructing A WinOrder: order(=vanishing moment) of window used for constructing test functions Out: aita[N]: corrected independent coefficients s2[LT]: reconstruct sinusoid BEFORE correction Returns the estimate of phase angle at 0. */ double AmpPhCorrectionExpA(cdouble* s2, int N, cdouble* aita, int L, int T, cdouble* sre, int M, double** h, double** dih, double*** A, void (*SpecifyA)(int L, int T, int M, int &N, double*** &A, MList* mlist, int mode), int WinOrder) { MList* mlist=new MList; //*amplitude and phase correction //amplitude is done by updating p, i.e. Re(aita) double *s2ph=new double[L+1]; mlist->Add(s2ph, 1); double *phcor=new double[L+1]; mlist->Add(phcor, 1); cdouble* lamda=new cdouble[M]; mlist->Add(lamda, 1); double* lamdax=new double[M]; mlist->Add(lamdax, 1); double* lamday=new double[M]; mlist->Add(lamday, 1); { double tmpph=0; memset(s2ph, 0, sizeof(double)*(L+1)); s2ph[0]=tmpph; for (int l=0; l<L; l++) { MultiplyXy(M, N, lamda, A[l], aita); for (int m=0; m<M; m++) lamdax[m]=lamda[m].x, lamday[m]=lamda[m].y; SinusoidExpA(T, &s2[l*T], M, lamdax, lamday, h, dih, tmpph); s2ph[l+1]=tmpph; } double* win=new double[2*T+1]; CosineWindows(WinOrder, 2*T, &win, 1); mlist->Add(win, 1); for (int l=1; l<L; l++) { cdouble inn=Inner(2*T, &sre[l*T-T], win, &s2[l*T-T])/Inner(2*T, &s2[l*T-T], win, &s2[l*T-T]); cdouble loginn=log(inn); if (SpecifyA==ssACubicHermite) { aita[l*2]+=loginn.x; s2ph[l]+=loginn.y; phcor[l]=loginn.y; if (l==1) aita[0]+=loginn.x, phcor[0]=loginn.y, s2ph[0]+=loginn.y; if (l==L-1) aita[L*2]+=loginn.x, phcor[L]=loginn.y, s2ph[L]+=loginn.y; } else { aita[l]+=loginn.x; s2ph[l]+=loginn.y; phcor[l]=loginn.y; if (l==1) { inn=Inner(T, sre, &win[T], s2)/Inner(T, s2, &win[T], s2); loginn=log(inn); aita[0]+=loginn.x; s2ph[0]+=loginn.y; phcor[0]=loginn.y; } if (l==L-1) { inn=Inner(T, &sre[L*T-T], win, &s2[L*T-T])/Inner(T, &s2[L*T-T], win, &s2[L*T-T]); loginn=log(inn); aita[L]+=loginn.x; s2ph[L]+=loginn.y; phcor[L]=loginn.y; } } } for (int l=1; l<=L; l++) { int k=floor((phcor[l]-phcor[l-1])/(2*M_PI)+0.5); if (k!=0) phcor[l]+=2*M_PI*k; } //* //now phcor[] contains phase corrector to be interpolated double *b=new double[L], *zet=new double[L+1], *dzet=new double[L+1]; memset(zet, 0, sizeof(double)*(L+1)); memset(dzet, 0, sizeof(double)*(L+1)); mlist->Add(b, 1); mlist->Add(zet, 1); mlist->Add(dzet, 1); double ihT[]={T, T/2.0*T, T/3.0*T*T, T/4.0*T*T*T}; Alloc2L(L, N, BB, mlist); //prepare linear system (BB)(zet)=(b) for (int l=0; l<L; l++) { MultiplyxY(N, 4, BB[l], ihT, A[l]); b[l]=phcor[l+1]-phcor[l]; } Alloc2L(L, L, copyA, mlist); if (L+1==N) for (int l=0; l<L; l++) memcpy(copyA[l], &BB[l][1], sizeof(double)*L); else if (L+1==N/2) for (int l=0; l<L; l++) for (int k=0; k<L; k++) copyA[l][k]=BB[l][2*k+2]; double* copyb=Copy(L, b, mlist); zet[0]=0; GECP(L, &zet[1], copyA, copyb); if (L+1==N) for (int l=0; l<L; l++) memcpy(copyA[l], &BB[l][1], sizeof(double)*L); else if (L+1==N/2) for (int l=0; l<L; l++) for (int k=0; k<L; k++) copyA[l][k]=BB[l][2*k+2]; Copy(L, copyb, b); for (int l=0; l<L; l++) copyb[l]-=BB[l][0]; dzet[0]=1; GECP(L, &dzet[1], copyA, copyb); #ifdef ERROR_CHECK //Test that (BB)(zet)=b and (BB)(dzet)=b double* bbzet=MultiplyXy(L, L+1, BB, zet, mlist); MultiAdd(L, bbzet, bbzet, b, -1); double err1=Inner(L, bbzet, bbzet); double* bbdzet=MultiplyXy(L, L+1, BB, dzet, mlist); MultiAdd(L, bbdzet, bbdzet, b, -1); double err2=Inner(L, bbdzet, bbdzet); MultiAdd(L+1, dzet, dzet, zet, -1); //Test that (BB)dzet=0 MultiplyXy(L, L+1, bbdzet, BB, dzet); double err3=Inner(L, bbzet, bbzet); #endif //now that (zet)+(miu)(dzet) is the general solution to (BB)(zet)=b, // we look for (miu) that maximizes smoothness double innuv=0, innvv=0, lmd0[4], lmdd[4], clmdd[4], T2=T*T, T3=T2*T, T4=T3*T, T5=T4*T; for (int l=0; l<L; l++) { MultiplyXy(4, L+1, lmd0, A[l], zet); MultiplyXy(4, L+1, lmdd, A[l], dzet); clmdd[1]=T*lmdd[1]+T2*lmdd[2]+T3*lmdd[3]; clmdd[2]=T2*lmdd[1]+(4.0/3)*T3*lmdd[2]+1.5*T4*lmdd[3]; clmdd[3]=T3*lmdd[1]+1.5*T4*lmdd[2]+1.8*T5*lmdd[3]; innuv+=Inner(3, &lmd0[1], &clmdd[1]); innvv+=Inner(3, &lmdd[1], &clmdd[1]); } MultiAdd(L+1, zet, zet, dzet, -innuv/innvv); if (SpecifyA==ssACubicHermite) for (int l=0; l<=L; l++) aita[2*l].y+=zet[l]; else for (int l=0; l<=L; l++) aita[l].y+=zet[l]; //*/ } double result=s2ph[0]; delete mlist; return result; }//AmpPhCorrectionExpA