xue@11: /* xue@11: Harmonic sinusoidal modelling and tools xue@11: xue@11: C++ code package for harmonic sinusoidal modelling and relevant signal processing. xue@11: Centre for Digital Music, Queen Mary, University of London. xue@11: This file copyright 2011 Wen Xue. xue@11: xue@11: This program is free software; you can redistribute it and/or xue@11: modify it under the terms of the GNU General Public License as xue@11: published by the Free Software Foundation; either version 2 of the xue@11: License, or (at your option) any later version. xue@11: */ xue@1: //--------------------------------------------------------------------------- xue@1: xue@1: #include Chris@2: #include "sinest.h" xue@1: #include "fft.h" xue@1: #include "opt.h" Chris@2: #include "sinsyn.h" xue@1: #include "splines.h" Chris@2: #include "windowfunctions.h" xue@1: Chris@5: /** \file sinest.h */ Chris@5: xue@1: //--------------------------------------------------------------------------- Chris@5: /** xue@1: function dsincd_unn: derivative of unnormalized discrete sinc function xue@1: xue@1: In: x, scale N xue@1: xue@1: Returns the derivative of sincd_unn(x, N) xue@1: */ xue@1: double dsincd_unn(double x, int N) xue@1: { xue@1: double r=0; xue@1: double omg=M_PI*x; xue@1: double domg=omg/N; xue@1: if (fabs(x)>1e-6) xue@1: { xue@1: r=M_PI*(cos(omg)-sin(omg)*cos(domg)/sin(domg)/N)/sin(domg); xue@1: } xue@1: else xue@1: { xue@1: if (domg!=0) xue@1: { xue@1: double sindomg=sin(domg); xue@1: r=-omg*omg*omg*(1-1.0/(1.0*N*N))/3*M_PI/N/sindomg/sindomg; xue@1: } xue@1: else xue@1: r=0; xue@1: } xue@1: return r; xue@1: }//dsincd_unn xue@1: Chris@5: /** xue@1: function ddsincd_unn: 2nd-order derivative of unnormalized discrete sinc function xue@1: xue@1: In: x, scale (equivalently, window size) N xue@1: xue@1: Returns the 2nd-order derivative of sincd_unn(x, N) xue@1: */ xue@1: double ddsincd_unn(double x, int N) xue@1: { xue@1: double r=0; xue@1: double omg=M_PI*x; xue@1: double domg=omg/N; xue@1: double PI2=M_PI*M_PI; xue@1: double NN=1.0/N/N-1; xue@1: if (domg==0) xue@1: { xue@1: r=PI2*N*NN/3; xue@1: } xue@1: else xue@1: { xue@1: if (fabs(x)>1e-5) xue@1: { xue@1: r=sin(domg)*cos(omg)-sin(omg)*cos(domg)/N; xue@1: } xue@1: else xue@1: { xue@1: r=omg*omg*omg/N*NN/3; xue@1: } xue@1: double ss=sin(omg)*NN; xue@1: r=-2.0/N*cos(domg)*r/sin(domg)/sin(domg)+ss; xue@1: r=r*PI2/sin(domg); xue@1: } xue@1: return r; xue@1: }//ddsincd_unn xue@1: xue@1: //--------------------------------------------------------------------------- Chris@5: /** xue@1: function Window: calculates the cosine-family-windowed spectrum of a complex sinusoid on [0:N-1] at xue@1: frequency f bins with zero central phase. xue@1: xue@1: In: f: frequency, in bins xue@1: N: window size xue@1: M, c[]: cosine-family window decomposition coefficients xue@1: Out: x[0...K2-K1] containing the spectrum at bins K1, ..., K2. xue@1: xue@1: Returns pointer to x. x is created anew if x=0 is specified on start. xue@1: */ xue@1: cdouble* Window(cdouble* x, double f, int N, int M, double* c, int K1, int K2) xue@1: { xue@1: if (K1<0) K1=0; xue@1: if (K2>N/2-1) K2=N/2-1; xue@1: xue@1: if (!x) x=new cdouble[K2-K1+1]; xue@1: memset(x, 0, sizeof(cdouble)*(K2-K1+1)); xue@1: xue@1: for (int l=K1-M; l<=K2+M; l++) xue@1: { xue@1: double ang=(f-l)*M_PI; xue@1: double omg=ang/N; xue@1: long double si, co, sinn=sin(ang); xue@1: si=sin(omg), co=cos(omg); xue@1: double sa=(ang==0)?N:(sinn/si); xue@1: double saco=sa*co; xue@1: xue@1: int k1=l-M, k2=l+M; xue@1: if (k1K2) k2=K2; xue@1: xue@1: for (int k=k1; k<=k2; k++) xue@1: { xue@1: int m=k-l, kt=k-K1; xue@1: if (m<0) m=-m; xue@1: if (k%2) xue@1: { xue@1: x[kt].x-=c[m]*saco; xue@1: x[kt].y+=c[m]*sinn; xue@1: } xue@1: else xue@1: { xue@1: x[kt].x+=c[m]*saco; xue@1: x[kt].y-=c[m]*sinn; xue@1: } xue@1: } xue@1: } xue@1: return x; xue@1: }//Window xue@1: Chris@5: /** xue@1: function dWindow: calculates the cosine-family-windowed spectrum and its derivative of a complex xue@1: sinusoid on [0:N-1] at frequency f bins with zero central phase. xue@1: xue@1: In: f: frequency, in bins xue@1: N: window size xue@1: M, c[]: cosine-family window decomposition coefficients xue@1: Out: x[0...K2-K1] containing the spectrum at bins K1, ..., K2, xue@1: dx[0...K2-K1] containing the derivative spectrum at bins K1, ..., K2 xue@1: xue@1: No return value. xue@1: */ xue@1: void dWindow(cdouble* dx, cdouble* x, double f, int N, int M, double* c, int K1, int K2) xue@1: { xue@1: if (K1<0) K1=0; xue@1: if (K2>N/2-1) K2=N/2-1; xue@1: memset(x, 0, sizeof(cdouble)*(K2-K1+1)); xue@1: memset(dx, 0, sizeof(cdouble)*(K2-K1+1)); xue@1: xue@1: for (int l=K1-M; l<=K2+M; l++) xue@1: { xue@1: double ang=(f-l), Omg=ang*M_PI, omg=Omg/N; xue@1: long double si, co, sinn=sin(Omg), cosn=cos(Omg); xue@1: si=sin(omg), co=cos(omg); xue@1: double sa=(ang==0)?N:(sinn/si), dsa=dsincd_unn(ang, N); xue@1: double saco=sa*co, dsaco=dsa*co, sinnpi_n=sinn*M_PI/N, cosnpi=cosn*M_PI; xue@1: xue@1: int k1=l-M, k2=l+M; xue@1: if (k1K2) k2=K2; xue@1: xue@1: for (int k=k1; k<=k2; k++) xue@1: { xue@1: int m=k-l, kt=k-K1; xue@1: if (m<0) m=-m; xue@1: if (k%2) xue@1: { xue@1: x[kt].x-=c[m]*saco; xue@1: x[kt].y+=c[m]*sinn; xue@1: dx[kt].x-=c[m]*(-sinnpi_n+dsaco); xue@1: dx[kt].y+=c[m]*cosnpi; xue@1: } xue@1: else xue@1: { xue@1: x[kt].x+=c[m]*saco; xue@1: x[kt].y-=c[m]*sinn; xue@1: dx[kt].x+=c[m]*(-sinnpi_n+dsaco); xue@1: dx[kt].y-=c[m]*cosnpi; xue@1: } xue@1: } xue@1: } xue@1: }//dWindow xue@1: Chris@5: /** xue@1: function ddWindow: calculates the cosine-family-windowed spectrum and its 1st and 2nd derivatives of xue@1: a complex sinusoid on [0:N-1] at frequency f bins with zero central phase. xue@1: xue@1: In: f: frequency, in bins xue@1: N: window size xue@1: M, c[]: cosine-family window decomposition coefficients xue@1: Out: x[0...K2-K1] containing the spectrum at bins K1, ..., K2, xue@1: dx[0...K2-K1] containing the derivative spectrum at bins K1, ..., K2 xue@1: ddx[0...K2-K1] containing the 2nd-order derivative spectrum at bins K1, ..., K2 xue@1: xue@1: No return value. xue@1: */ xue@1: void ddWindow(cdouble* ddx, cdouble* dx, cdouble* x, double f, int N, int M, double* c, int K1, int K2) xue@1: { xue@1: if (K1<0) K1=0; xue@1: if (K2>N/2-1) K2=N/2-1; xue@1: memset(x, 0, sizeof(cdouble)*(K2-K1+1)); xue@1: memset(dx, 0, sizeof(cdouble)*(K2-K1+1)); xue@1: memset(ddx, 0, sizeof(cdouble)*(K2-K1+1)); xue@1: xue@1: for (int l=K1-M; l<=K2+M; l++) xue@1: { xue@1: double ang=(f-l), Omg=ang*M_PI, omg=Omg/N; xue@1: long double si, co, sinn=sin(Omg), cosn=cos(Omg); xue@1: si=sin(omg), co=cos(omg); xue@1: double sa=(ang==0)?N:(sinn/si), dsa=dsincd_unn(ang, N), ddsa=ddsincd_unn(ang, N); xue@1: double saco=sa*co, dsaco=dsa*co, sinnpi_n=sinn*M_PI/N, sinnpipi=sinn*M_PI*M_PI, cosnpi=cosn*M_PI, xue@1: cosnpipi_n=cosnpi*M_PI/N, sipi_n=si*M_PI/N; xue@1: xue@1: int k1=l-M, k2=l+M; xue@1: if (k1K2) k2=K2; xue@1: xue@1: for (int k=k1; k<=k2; k++) xue@1: { xue@1: int m=k-l, kt=k-K1; xue@1: if (m<0) m=-m; xue@1: if (k%2) xue@1: { xue@1: x[kt].x-=c[m]*saco; xue@1: x[kt].y+=c[m]*sinn; xue@1: dx[kt].x-=c[m]*(-sinnpi_n+dsaco); xue@1: dx[kt].y+=c[m]*cosnpi; xue@1: ddx[kt].x-=c[m]*(-cosnpipi_n+ddsa*co-dsa*sipi_n); xue@1: ddx[kt].y-=c[m]*sinnpipi; xue@1: } xue@1: else xue@1: { xue@1: x[kt].x+=c[m]*saco; xue@1: x[kt].y-=c[m]*sinn; xue@1: dx[kt].x+=c[m]*(-sinnpi_n+dsaco); xue@1: dx[kt].y-=c[m]*cosnpi; xue@1: ddx[kt].x+=c[m]*(-cosnpipi_n+ddsa*co-dsa*sipi_n); xue@1: ddx[kt].y+=c[m]*sinnpipi; xue@1: } xue@1: } xue@1: } xue@1: }//ddWindow xue@1: xue@1: //--------------------------------------------------------------------------- Chris@5: /** xue@1: function IPWindow: computes the truncated inner product of a windowed spectrum with that of a sinusoid xue@1: at reference frequency f. xue@1: xue@1: In: x[0:N-1]: input spectrum xue@1: f: reference frequency, in bins xue@1: M, c[], iH2: cosine-family window specification parameters xue@1: K1, K2: spectrum truncation bounds, in bins, inclusive xue@1: returnamplitude: specifies return value, true for amplitude, false for angle xue@1: xue@1: Returns the amplitude or phase of the inner product, as specified by $returnamplitude. The return xue@1: value is interpreted as the actual amplitude/phase of a sinusoid being estimated at f. xue@1: */ xue@1: double IPWindow(double f, cdouble* x, int N, int M, double* c, double iH2, int K1, int K2, bool returnamplitude) xue@1: { xue@1: cdouble r=IPWindowC(f, x, N, M, c, iH2, K1, K2); xue@1: double result; xue@1: if (returnamplitude) result=sqrt(r.x*r.x+r.y*r.y); xue@1: else result=arg(r); xue@1: return result; xue@1: }//IPWindow xue@1: //wrapper function xue@1: double IPWindow(double f, void* params) xue@1: { xue@1: 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; xue@1: return IPWindow(f, p->x, p->N, p->M, p->c, p->iH2, p->k1, p->k2, true); xue@1: }//IPWindow xue@1: Chris@5: /** xue@1: function ddIPWindow: computes the norm of the truncated inner product of a windowed spectrum with xue@1: that of a sinusoid at reference frequency f, as well as its 1st and 2nd derivatives. xue@1: xue@1: In: x[0:N-1]: input spectrum xue@1: f: reference frequency, in bins xue@1: M, c[], iH2: cosine-family window specification parameters xue@1: K1, K2: spectrum truncation bounds, in bins, inclusive xue@1: Out: ipwindow and dipwindow: the truncated inner product norm and its derivative xue@1: xue@1: Returns the 2nd derivative of the norm of the truncated inner product. xue@1: */ xue@1: double ddIPWindow(double f, cdouble* x, int N, int M, double* c, double iH2, int K1, int K2, double& dipwindow, double& ipwindow) xue@1: { xue@1: if (K1<0) K1=0; if (K2>=N/2) K2=N/2-1; xue@1: int K=K2-K1+1; xue@1: cdouble *w=new cdouble[K*3], *dw=&w[K], *ddw=&w[K*2], *lx=&x[K1]; xue@1: ddWindow(ddw, dw, w, f, N, M, c, K1, K2); xue@1: cdouble r=Inner(K, lx, w), dr=Inner(K, lx, dw), ddr=Inner(K, lx, ddw); xue@1: delete[] w; xue@1: xue@1: double R2=~r, xue@1: R=sqrt(R2), xue@1: dR2=2*(r.x*dr.x+r.y*dr.y), xue@1: dR=dR2/(2*R), xue@1: ddR2=2*(r.x*ddr.x+r.y*ddr.y+~dr), xue@1: ddR=(R*ddR2-dR2*dR)/(2*R2); xue@1: ipwindow=R*iH2; xue@1: dipwindow=dR*iH2; xue@1: return ddR*iH2; xue@1: }//ddIPWindow xue@1: //wrapper function xue@1: double ddIPWindow(double f, void* params) xue@1: { xue@1: 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; xue@1: return ddIPWindow(f, p->x, p->N, p->M, p->c, p->iH2, p->k1, p->k2, p->dipwindow, p->ipwindow); xue@1: }//ddIPWindow xue@1: xue@1: //--------------------------------------------------------------------------- Chris@5: /** xue@1: function IPWindowC: computes the truncated inner product of a windowed spectrum with that of a xue@1: sinusoid at reference frequency f. xue@1: xue@1: In: x[0:N-1]: input spectrum xue@1: f: reference frequency, in bins xue@1: M, c[], iH2: cosine-family window specification parameters xue@1: K1, K2: spectrum truncation bounds, in bins, inclusive xue@1: xue@1: Returns the inner product. The return value is interpreted as the actual amplitude-phase factor of a xue@1: sinusoid being estimated at f. xue@1: */ xue@1: cdouble IPWindowC(double f, cdouble* x, int N, int M, double* c, double iH2, int K1, int K2) xue@1: { xue@1: if (K1<0) K1=0; if (K2>=N/2) K2=N/2-1; xue@1: int K=K2-K1+1; xue@1: cdouble *w=new cdouble[K]; xue@1: cdouble *lx=&x[K1], result=0; xue@1: Window(w, f, N, M, c, K1, K2); xue@1: for (int k=0; k=N/2) K2=N/2-1; xue@1: int K=K2-K1+1; xue@1: cdouble *w=new cdouble[K]; xue@1: Window(w, f, N, M, c, K1, K2); xue@1: for (int l=0; lFr, p->x, p->N, p->M, p->c, p->iH2, p->k1, p->k2, p->lmd); xue@1: }//sIPWindow xue@1: Chris@5: /** xue@1: function dsIPWindow: computes the total energy of truncated inner products between multiple windowed xue@1: spectra and that of a sinusoid at a reference frequency f, as well as its derivative. This does not xue@1: consider phase synchronization between the spectra, supposedly measured at a sequence of known xue@1: instants. xue@1: xue@1: In: x[L][N]: input spectra xue@1: f: reference frequency, in bins xue@1: M, c[], iH2: cosine-family window specification parameters xue@1: K1, K2: spectrum truncation bounds, in bins, inclusive xue@1: Out: sip, the energy of the vector of inner products. xue@1: xue@1: Returns the derivative of the energy of the vector of inner products. xue@1: */ xue@1: double dsIPWindow(double f, int L, cdouble** x, int N, int M, double* c, double iH2, int K1, int K2, double& sip) xue@1: { xue@1: if (K1<0) K1=0; if (K2>=N/2) K2=N/2-1; xue@1: int K=K2-K1+1; xue@1: cdouble *w=new cdouble[K*2], *dw=&w[K]; xue@1: dWindow(dw, w, f, N, M, c, K1, K2); xue@1: double dsip; sip=0; xue@1: for (int l=0; lFr, p->x, p->N, p->M, p->c, p->iH2, p->k1, p->k2, p->sip); xue@1: }//dsIPWindow xue@1: Chris@5: /** xue@1: function dsdIPWindow_unn: computes the energy of unnormalized truncated inner products between a given xue@1: windowed spectrum and that of a sinusoid at a reference frequency f, as well as its 1st and 2nd xue@1: derivatives. "Unnormalized" indicates that the inner product cannot be taken as the actual amplitude- xue@1: phase factor of a sinusoid, but deviate from that by an unspecified factor. xue@1: xue@1: In: x[N]: input spectrum xue@1: f: reference frequency, in bins xue@1: M, c[], iH2: cosine-family window specification parameters xue@1: K1, K2: spectrum truncation bounds, in bins, inclusive xue@1: Out: sipwindow and dsipwindow, the energy and its derivative of the unnormalized inner product. xue@1: xue@1: Returns the 2nd derivative of the inner product. xue@1: */ xue@1: double ddsIPWindow_unn(double f, cdouble* x, int N, int M, double* c, int K1, int K2, double& dsipwindow, double& sipwindow, cdouble* w_unn) xue@1: { xue@1: if (K1<0) K1=0; if (K2>=N/2) K2=N/2-1; xue@1: int K=K2-K1+1; xue@1: xue@1: cdouble *w=new cdouble[K*3], *dw=&w[K], *ddw=&w[K*2]; xue@1: xue@1: ddWindow(ddw, dw, w, f, N, M, c, K1, K2); xue@1: xue@1: double rr=0, ri=0, drr=0, dri=0, ddrr=0, ddri=0; xue@1: cdouble *lx=&x[K1]; xue@1: for (int k=0; kx=rr, w_unn->y=ri; xue@1: return ddR2; xue@1: }//ddsIPWindow_unn xue@1: Chris@5: /** xue@1: function ddsIPWindow: computes the total energy of truncated inner products between multiple windowed xue@1: spectra and that of a sinusoid at a reference frequency f, as well as its 1st and 2nd derivatives. xue@1: This does not consider phase synchronization between the spectra, supposedly measured at a sequence xue@1: of known instants. xue@1: xue@1: In: x[L][N]: input spectra xue@1: f: reference frequency, in bins xue@1: M, c[], iH2: cosine-family window specification parameters xue@1: K1, K2: spectrum truncation bounds, in bins, inclusive xue@1: Out: sip and dsip, the energy of the vector of inner products and its derivative. xue@1: xue@1: Returns the 2nd derivative of the energy of the vector of inner products. xue@1: */ xue@1: double ddsIPWindow(double f, int L, cdouble** x, int N, int M, double* c, double iH2, int K1, int K2, double& dsip, double& sip) xue@1: { xue@1: if (K1<0) K1=0; if (K2>=N/2) K2=N/2-1; xue@1: int K=K2-K1+1; xue@1: cdouble *w=new cdouble[K*3], *dw=&w[K], *ddw=&w[K*2]; xue@1: ddWindow(ddw, dw, w, f, N, M, c, K1, K2); xue@1: double ddsip=0; dsip=sip=0; xue@1: for (int l=0; lFr, p->x, p->N, p->M, p->c, p->iH2, p->k1, p->k2, p->dsip, p->sip); xue@1: }//ddsIPWindow xue@1: xue@1: //--------------------------------------------------------------------------- Chris@5: /** xue@1: function sIPWindowC: computes the total energy of truncated inner products between multiple frames of xue@1: a spectrogram and multiple frames of a spectrogram of a sinusoid at a reference frequency f. xue@1: xue@1: In: x[L][N]: the spectrogram xue@1: offst_rel: frame offset, relative to frame size xue@1: f: reference frequency, in bins xue@1: M, c[], iH2: cosine-family window specification parameters xue@1: K1, K2: spectrum truncation bounds, in bins, inclusive xue@1: Out: lmd[L]: the actual individual inner products representing actual ampltiude-phase factors (optional) xue@1: xue@1: Returns the energy of the vector of inner products. xue@1: */ xue@1: 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) xue@1: { xue@1: if (K1<0) K1=0; if (K2>=N/2) K2=N/2-1; xue@1: int K=K2-K1+1; xue@1: cdouble *w=new cdouble[K]; xue@1: double Cr=0; xue@1: cdouble Cc=0; xue@1: Window(w, f, N, M, c, K1, K2); xue@1: for (int l=0; lL, p->offst_rel, p->x, p->N, p->M, p->c, p->iH2, p->k1, p->k2); xue@1: }//sIPWindowC xue@1: Chris@5: /** xue@1: function dsIPWindowC: computes the total energy of truncated inner products between multiple frames of xue@1: a spectrogram and multiple frames of a spectrogram of a sinusoid at a reference frequency f, together xue@1: with its derivative. xue@1: xue@1: In: x[L][N]: the spectrogram xue@1: offst_rel: frame offset, relative to frame size xue@1: f: reference frequency, in bins xue@1: M, c[], iH2: cosine-family window specification parameters xue@1: K1, K2: spectrum truncation bounds, in bins, inclusive xue@1: Out: sip: energy of the vector of the inner products xue@1: xue@1: Returns the 1st derivative of the energy of the vector of inner products. xue@1: */ xue@1: 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) xue@1: { xue@1: if (K1<0) K1=0; if (K2>=N/2) K2=N/2-1; xue@1: int K=K2-K1+1; xue@1: xue@1: cdouble *w=new cdouble[K*2], *dw=&w[K]; xue@1: dWindow(dw, w, f, N, M, c, K1, K2); xue@1: double Cr=0, dCr=0; xue@1: cdouble Cc=0, dCc=0; xue@1: for (int l=0; lL, p->offst_rel, p->x, p->N, p->M, p->c, p->iH2, p->k1, p->k2, p->sip); xue@1: }//dsIPWindowC xue@1: Chris@5: /** xue@1: function ddsIPWindowC: computes the total energy of truncated inner products between multiple frames xue@1: of a spectrogram and multiple frames of a spectrogram of a sinusoid at a reference frequency f, xue@1: together with its 1st and 2nd derivatives. xue@1: xue@1: In: x[L][N]: the spectrogram xue@1: offst_rel: frame offset, relative to frame size xue@1: f: reference frequency, in bins xue@1: M, c[], iH2: cosine-family window specification parameters xue@1: K1, K2: spectrum truncation bounds, in bins, inclusive xue@1: Out: sipwindow, dsipwindow: energy of the vector of the inner products and its derivative xue@1: xue@1: Returns the 2nd derivative of the energy of the vector of inner products. xue@1: */ xue@1: 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) xue@1: { xue@1: if (K1<0) K1=0; if (K2>=N/2) K2=N/2-1; xue@1: int K=K2-K1+1; xue@1: xue@1: cdouble *w=new cdouble[K*3], *dw=&w[K], *ddw=&w[K*2]; xue@1: ddWindow(ddw, dw, w, f, N, M, c, K1, K2); xue@1: double Cr=0, dCr=0, ddCr=0; xue@1: cdouble Cc=0, dCc=0, ddCc=0; xue@1: for (int l=0; lL, p->offst_rel, p->x, p->N, p->M, p->c, p->iH2, p->k1, p->k2, p->dipwindow, p->ipwindow); xue@1: }//ddsIPWindowC xue@1: xue@1: //-------------------------------------------------------------------------- xue@1: /* xue@1: Least-square-error sinusoid detection function xue@1: xue@1: version1: picking the highest peak and take measurement of a single sinusoid xue@1: version2: given a rough peak location and take measurement of a single sinusoid xue@1: xue@1: Complex spectrum x is calculated using N data points windowed by a window function that is specified xue@1: by the parameter set (M, c, iH2). c[0:M] is provided according to Table 3 in the transfer report, on xue@1: pp.11. iH2 is simply 1/H2, where H2 can be calculated using formula (2.17) on pp.12. xue@1: xue@1: f & epf are given/returned in bins. xue@1: xue@1: Further reading: "Least-square-error estimation of sinusoids.pdf" xue@1: */ xue@1: Chris@5: /** xue@1: function LSESinusoid: LSE estimation of the predominant stationary sinusoid. xue@1: xue@1: In: x[N]: windowed spectrum xue@1: B: spectral truncation half width, in bins. xue@1: M, c[], iH2: cosine-family window specification parameters xue@1: epf: frequency error tolerance, in bins xue@1: Out: a and pp: amplitude and phase estimates xue@1: xue@1: Returns the frequency estimate, in bins. xue@1: */ xue@1: double LSESinusoid(cdouble* x, int N, double B, int M, double* c, double iH2, double& a, double& pp, double epf) xue@1: { xue@1: 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; Chris@3: int dfshift=offsetof(l_hx, dhxpeak); xue@1: xue@1: int inp; xue@1: double minp=0; xue@1: for (int i=0; i=p.N/2) p.k2=p.N/2-1; xue@1: tmp=IPWindow(lf, &p); xue@1: if (minp=p.N/2) p.k2=p.N/2-1; xue@1: double tmp=Newton(f, ddIPWindow, &p, dfshift, epf); xue@1: if (tmp==-1) xue@1: { xue@1: Search1Dmax(f, &p, IPWindow, inp-1, inp+1, &a, epf); xue@1: } xue@1: else xue@1: a=p.hxpeak; xue@1: pp=IPWindow(f, x, N, M, c, iH2, p.k1, p.k2, false); xue@1: return f; xue@1: }//LSESinusoid xue@1: xue@1: /*function LSESinusoid: LSE estimation of stationary sinusoid near a given initial frequency. xue@1: xue@1: In: x[N]: windowed spectrum xue@1: f: initial frequency, in bins xue@1: B: spectral truncation half width, in bins. xue@1: M, c[], iH2: cosine-family window specification parameters xue@1: epf: frequency error tolerance, in bins xue@1: Out: f, a and pp: frequency, amplitude and phase estimates xue@1: xue@1: No return value. xue@1: */ xue@1: void LSESinusoid(double& f, cdouble* x, int N, double B, int M, double* c, double iH2, double& a, double& pp, double epf) xue@1: { xue@1: 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}; Chris@3: int dfshift=offsetof(l_hx, dhxpeak); xue@1: xue@1: double inp=f; xue@1: p.k1=ceil(inp-B); if (p.k1<0) p.k1=0; xue@1: p.k2=floor(inp+B); if (p.k2>=p.N/2) p.k2=p.N/2-1; xue@1: double tmp=Newton(f, ddIPWindow, &p, dfshift, epf); xue@1: if (tmp==-1) xue@1: { xue@1: Search1Dmax(f, &p, IPWindow, inp-1, inp+1, &a, epf); xue@1: } xue@1: else xue@1: a=p.hxpeak; xue@1: pp=IPWindow(f, x, N, M, c, iH2, p.k1, p.k2, false); xue@1: }//LSESinusoid xue@1: Chris@5: /** xue@1: function LSESinusoid: LSE estimation of stationary sinusoid predominant within [f1, f2]. xue@1: xue@1: In: x[N]: windowed spectrum xue@1: [f1, f2]: frequency range xue@1: B: spectral truncation half width, in bins. xue@1: M, c[], iH2: cosine-family window specification parameters xue@1: epf: frequency error tolerance, in bins xue@1: Out: a and pp: amplitude and phase estimates xue@1: xue@1: Returns the frequency estimate, in bins. xue@1: */ xue@1: double LSESinusoid(int f1, int f2, cdouble* x, int N, double B, int M, double* c, double iH2, double& a, double& pp, double epf) xue@1: { xue@1: 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}; Chris@3: int dfshift=offsetof(l_hx, dhxpeak); xue@1: xue@1: int inp; xue@1: double minp=0; xue@1: for (int i=f1; i=p.N/2) p.k2=p.N/2-1; xue@1: tmp=IPWindow(lf, &p); xue@1: if (minp=p.N/2) p.k2=p.N/2-1; xue@1: double tmp=Newton(f, ddIPWindow, &p, dfshift, epf); xue@1: if (tmp==-1) xue@1: { xue@1: Search1Dmax(f, &p, IPWindow, inp-1, inp+1, &a, epf); xue@1: } xue@1: else xue@1: a=p.hxpeak; xue@1: pp=IPWindow(f, x, N, M, c, iH2, p.k1, p.k2, false); xue@1: return f; xue@1: }//LSESinusoid xue@1: Chris@5: /** xue@1: function LSESinusoid: LSE estimation of stationary sinusoid near a given initial frequency within [f1, xue@1: f2]. xue@1: xue@1: In: x[N]: windowed spectrum xue@1: f: initial frequency, in bins xue@1: [f1, f2]: frequency range xue@1: B: spectral truncation half width, in bins. xue@1: M, c[], iH2: cosine-family window specification parameters xue@1: epf: frequency error tolerance, in bins xue@1: Out: f, a and pp: frequency, amplitude and phase estimates xue@1: xue@1: Returns 1 if managed to find a sinusoid, 0 if not, upon which $a and $pp are estimated at the initial xue@1: f. xue@1: */ xue@1: 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) xue@1: { xue@1: 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; Chris@3: int dfshift=offsetof(l_hx, dhxpeak); xue@1: xue@1: int result=0; xue@1: double inp=f; xue@1: p.k1=ceil(inp-B); if (p.k1<0) p.k1=0; xue@1: p.k2=floor(inp+B); if (p.k2>=p.N/2) p.k2=p.N/2-1; xue@1: double tmp=Newton(f, ddIPWindow, &p, dfshift, epf, 100, 1e-256, f1, f2); xue@1: if (tmp!=-1 && f>f1 && f=f2) xue@1: { xue@1: f=inp; xue@1: cdouble r=IPWindowC(f, x, N, M, c, iH2, p.k1, p.k2); xue@1: a=abs(r); xue@1: pp=arg(r); xue@1: } xue@1: else xue@1: { xue@1: result=1; xue@1: pp=IPWindow(f, x, N, M, c, iH2, p.k1, p.k2, false); xue@1: } xue@1: } xue@1: return result; xue@1: }//LSESinusoid xue@1: Chris@5: /** xue@1: function LSESinusoidMP: LSE estimation of a stationary sinusoid from multi-frames spectrogram without xue@1: considering phase-frequency consistency across frames. xue@1: xue@1: In: x[Fr][N]: spectrogram xue@1: f: initial frequency, in bins xue@1: [f1, f2]: frequency range xue@1: B: spectral truncation half width, in bins. xue@1: M, c[], iH2: cosine-family window specification parameters xue@1: epf: frequency error tolerance, in bins xue@1: Out: f, a[Fr] and ph[Fr]: frequency, amplitudes and phase angles estimates xue@1: xue@1: Returns an error bound of the frequency estimate. xue@1: */ xue@1: 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) xue@1: { xue@1: 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}; Chris@3: int dfshift=offsetof(l_ip1, dsip), fshift=offsetof(l_ip1, sip); xue@1: xue@1: double inp=f; xue@1: p.k1=ceil(inp-B); if (p.k1<0) p.k1=0; xue@1: p.k2=floor(inp+B); if (p.k2>=p.N/2) p.k2=p.N/2-1; xue@1: double errf=Newton1dmax(f, f1, f2, ddsIPWindow, &p, dfshift, fshift, dsIPWindow, dfshift, epf); xue@1: if (errf<0) errf=Search1Dmax(f, &p, sIPWindow, f1, f2, a, epf); xue@1: if (a || ph) xue@1: { xue@1: for (int fr=0; fr=p.N/2) p.k2=p.N/2-1; xue@1: double errf=Newton1dmax(f, f1, f2, ddsIPWindowC, &p, dfshift, fshift, dsIPWindowC, dfshift, epf); xue@1: if (errf<0) errf=Search1Dmax(f, &p, sIPWindowC, f1, f2, a, epf); xue@1: if (a || ph) xue@1: { xue@1: cdouble* lmd=new cdouble[Fr]; xue@1: sIPWindowC(f, Fr, Offst*1.0/N, x, N, M, c, iH2, p.k1, p.k2, lmd); xue@1: for (int fr=0; fr=Wid/2) K2=Wid/2-1; int K=K2-K1+1; xue@1: MList* List=new MList; xue@1: cdouble** Allocate2L(cdouble, I, K, wt, List); xue@1: for (int i=0; i=Wid/2) K2=Wid/2-1; int K=K2-K1+1; xue@1: MList* List=new MList; xue@1: cdouble** Allocate2L(cdouble, I, K, wt, List); xue@1: for (int i=0; i=Wid/2) K2=Wid/2-1; int K=K2-K1+1; xue@1: MList* List=new MList; xue@1: cdouble** Allocate2L(cdouble, I, K, wt, List); xue@1: for (int i=0; i0 && f[i]-f[i-1]>Bw) || i==I-1) xue@1: { xue@1: if (i==I-1) i++; xue@1: //process frequencies from ist to i-1 xue@1: if (i-1==ist) //one sinusoid xue@1: { xue@1: double fb=f[ist]; int K1=floor(fb-B+0.5), K2=floor(fb+B+0.5); xue@1: lmd[ist]=IPWindowC(fb, x, Wid, M, c, iH2, K1, K2); xue@1: } xue@1: else xue@1: { xue@1: MList* List=new MList; xue@1: int N=i-ist, K1=floor(f[ist]-B+0.5), K2=floor(f[i-1]+B+0.5), K=K2-K1+1; xue@1: cdouble** Allocate2L(cdouble, N, K, wt, List); xue@1: for (int n=0; n0 && f[i]-f[i-1]>Bw) || i==I-1) xue@1: { xue@1: if (i==I-1) i++; xue@1: xue@1: //process frequencies from ist to i-1 xue@1: if (i-1==ist) //one sinusoid xue@1: { xue@1: double fb=f[ist]; xue@1: cdouble* w=Window(0, fb, Wid, M, c, 0, hWid-1); xue@1: for (int k=0; k0 && f[i]-f[i-1]>Bw) || i==I-1) xue@1: { xue@1: if (i==I-1) i++; xue@1: xue@1: //process frequencies from ist to i-1 xue@1: if (i-1==ist) //one sinusoid xue@1: { xue@1: double fb=f[ist]; xue@1: cdouble* w=Window(0, fb, Wid, M, c, 0, hWid-1); xue@1: for (int k=0; kx=wr, w->y=wi; xue@1: double result=wr*wr+wi*wi; xue@1: return result; xue@1: }//WindowDuo xue@1: Chris@5: /** xue@1: function ddWindowDuo: calcualtes the square norm of the inner product between windowed spectra of two xue@1: sinusoids at frequencies f1 and f2, df=f1-f2, with its 1st and 2nd derivatives xue@1: xue@1: In: df: frequency difference, in bins xue@1: N: DFT size xue@1: M, d[]: cosine-family window specification parameters (see "further reading" for d[]). xue@1: Out: w[0], the inner product, optional xue@1: window, dwindow: square norm and its derivative, of the inner product xue@1: xue@1: Returns 2nd derivative of the square norm of the inner product. xue@1: */ xue@1: double ddWindowDuo(double df, int N, double* d, int M, double& dwindow, double& window, cdouble* w) xue@1: { xue@1: 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; xue@1: for (int m=-2*M; m<=2*M; m++) xue@1: { xue@1: double ang=df+m, Omg=ang*M_PI, omg=Omg/N; xue@1: double si=sin(omg), co=cos(omg), sinn=sin(Omg), cosn=cos(Omg); xue@1: double sa=(ang==0)?N:(sinn/si), dsa=dsincd_unn(ang, N), ddsa=ddsincd_unn(ang, N); xue@1: double dm; if (m<0) dm=d[-m]; else dm=d[m]; xue@1: wr+=dm*sa*co, wi+=-dm*sinn; xue@1: dwr+=dm*(dsa*co-PI_N*sinn), dwi+=-dm*M_PI*cosn; xue@1: ddwr+=dm*(ddsa*co-PI_N*dsa*si-PIPI_N*cosn), ddwi+=dm*PIPI*sinn; xue@1: } xue@1: wr*=N, wi*=N, dwr*=N, dwi*=N, ddwr*=N, ddwi*=N; xue@1: window=wr*wr+wi*wi; xue@1: dwindow=2*(wr*dwr+wi*dwi); xue@1: if (w) w->x=wr, w->y=wi; xue@1: double ddwindow=2*(wr*ddwr+dwr*dwr+wi*ddwi+dwi*dwi); xue@1: return ddwindow; xue@1: }//ddWindowDuo xue@1: Chris@5: /** xue@1: function sIPWindowDuo: calculates the square norm of the orthogonal projection of a windowed spectrum xue@1: onto the linear span of the windowed spectra of two sinusoids at reference frequencies f1 and f2. xue@1: xue@1: In: x[N]: spectrum xue@1: f1, f2: reference frequencies. xue@1: M, c[], d[], iH2: cosine-family window specification parameters. xue@1: K1, K2: spectrum truncation range, i.e. bins outside [K1, K2] are ignored. xue@1: Out: lmd1, lmd2: projection coefficients, interpreted as actual amplitude-phase factors xue@1: xue@1: Returns the square norm of the orthogonal projection. xue@1: */ xue@1: 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) xue@1: { xue@1: int K=K2-K1+1; xue@1: cdouble xw1=0, *lx=&x[K1], *w1=new cdouble[K*2], *r1=&w1[K]; xue@1: Window(w1, f1, N, M, c, K1, K2); xue@1: double w1w1=0; xue@1: for (int k=0; kf1, f2, p->x, p->N, p->c, p->d, p->M, p->iH2, p->k1, p->k2, r1, r2); xue@1: }//sIPWindowDuo xue@1: Chris@5: /** xue@1: function ddsIPWindowDuo: calculates the square norm, and its 1st and 2nd derivatives against f2,, of xue@1: the orthogonal projection of a windowed spectrum onto the linear span of the windowed spectra of two xue@1: sinusoids at reference frequencies f1 and f2. xue@1: xue@1: In: x[N]: spectrum xue@1: f1, f2: reference frequencies. xue@1: M, c[], d[], iH2: cosine-family window specification parameters. xue@1: K1, K2: spectrum truncation range, i.e. bins outside [K1, K2] are ignored. xue@1: xue@1: Out: lmd1, lmd2: projection coefficients, interpreted as actual amplitude-phase factors xue@1: ddsip[3]: the 2nd, 1st and 0th derivatives (against f2) of the square norm. xue@1: xue@1: No return value. xue@1: */ xue@1: 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) xue@1: { xue@1: int K=K2-K1+1; xue@1: cdouble xw1=0, *lx=&x[K1], *w1=new cdouble[K*2], *r1=&w1[K]; xue@1: Window(w1, f1, N, M, c, K1, K2); xue@1: double w1w1=0; xue@1: for (int k=0; kf1, f2, p->x, p->N, p->c, p->d, p->M, p->iH2, p->k1, p->k2, r1, r2); xue@1: p->dipwindow=ddsip2[1], p->ipwindow=ddsip2[2]; xue@1: return ddsip2[0]; xue@1: }//ddsIPWindowDuo xue@1: Chris@5: /** xue@1: function LSEDuo: least-square estimation of two sinusoids of which one has a fixed frequency xue@1: xue@1: In: x[N]: the windowed spectrum xue@1: f1: the fixed frequency xue@1: f2: initial value of the flexible frequency xue@1: fmin, fmax: search range for f2, the flexible frequency xue@1: B: spectral truncation half width xue@1: M, c[], d[], iH2: xue@1: epf: frequency error tolerance xue@1: Out: f2: frequency estimate xue@1: lmd1, lmd2: amplitude-phase factor estimates xue@1: Returns 1 if managed to find a good f2, 0 if not, upon which the initial f2 is used for estimating xue@1: xue@1: amplitudes and phase angles. xue@1: */ xue@1: 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) xue@1: { xue@1: int result=0; xue@1: double inp=f2; xue@1: int k1=ceil(inp-B); if (k1<0) k1=0; xue@1: int k2=floor(inp+B); if (k2>=N/2) k2=N/2-1; xue@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}; Chris@3: int dfshift=offsetof(l_hx, dipwindow);// fshift=int(&((l_hx*)0)->ipwindow); xue@1: xue@1: double tmp=Newton(f2, ddsIPWindowDuo, &p, dfshift, epf, 100, 1e-256, fmin, fmax); xue@1: if (tmp!=-1 && f2>fmin && f2=fmax) f2=inp; xue@1: else result=1; xue@1: } xue@1: sIPWindowDuo(f1, f2, x, N, c, d, M, iH2, k1, k2, r1, r2); xue@1: return result; xue@1: }//LSEDuo xue@1: xue@1: //--------------------------------------------------------------------------- xue@1: /* xue@1: Time-frequency reassignment sinusoid estimation routines. xue@1: xue@1: Further reading: A. R?bel, ¡°Estimating partial frequency and frequency slope using reassignment xue@1: operators,¡± in Proc. ICMC¡¯02. G?teborg. 2002. xue@1: */ xue@1: Chris@5: /** xue@1: function CDFTW: single-frequency windowed DTFT, centre-aligned xue@1: xue@1: In: data[Wid]: waveform data x xue@1: win[Wid+1]: window function xue@1: k: frequency, in bins, where bin=1/Wid xue@1: Out: X: DTFT of xw at frequency k bins xue@1: xue@1: No return value. xue@1: */ xue@1: void CDFTW(cdouble& X, double k, int Wid, cdouble* data, double* win) xue@1: { xue@1: X=0; xue@1: int hWid=Wid/2; xue@1: for (int i=0; i6) logaslope=6.0/Wid; xue@1: else if (logaslope*Wid<-6) logaslope=-6.0/Wid; xue@1: xue@1: f=f+fslope*(t-localt); //obtain frequency estimate at t xue@1: xue@1: cdouble x=0; xue@1: if (win==0) xue@1: { xue@1: for (int n=0; n0.5){} xue@1: } xue@1: xue@1: cdouble *y=new cdouble[Count]; xue@1: double *lf=new double[Count*4], *la=&lf[Count], *lp=&lf[Count*2], *lda=&lf[Count*3]; xue@1: xue@1: __int16* ref=new __int16[Count]; xue@1: for (int i=0; i1) xue@1: { xue@1: afr[fr]=a, pfr[fr]=fai, ffr[fr]=f; xue@1: } xue@1: else xue@1: { xue@1: double rr=a*cos(fai)+b*cos(thet); xue@1: double ii=a*sin(fai)+b*sin(thet); xue@1: 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)); xue@1: afr[fr]=sqrt(rr*rr+ii*ii); xue@1: pfr[fr]=atan2(ii, rr); xue@1: } xue@1: if (LogA) afr[fr]=log(afr[fr]); xue@1: } xue@1: CubicSpline(Fr-1, fa, fb, fc, fd, xs, ffr, 1, 1); xue@1: CubicSpline(Fr-1, aa, ab, ac, ad, xs, afr, 1, 1); xue@7: for (int fr=0; fr0.5){} xue@1: } xue@1: delete[] y; delete[] lf; delete[] ref; xue@1: }//AdditiveUpdate xue@1: Chris@5: /** xue@1: function AdditiveAnalyzer: sinusoid analyzer with one additive update xue@1: xue@1: In: x[Count]: waveform data xue@1: Wid, Offst: frame size and hop size xue@1: BasicAnalyzer: pointer to a sinusoid analyzer xue@1: ref[Count]: reference frequencies, in bins, used by BasicAnalyzer xue@1: BasicAnalyzer: pointer to a sinusoid analyzer xue@1: LogA: indicates if amplitudes are interpolated at cubic spline or exponential cubic spline xue@1: Out: fs[Count], as[Count], phs[Count]: sinusoid parameter estimates xue@1: das[Count]: estimate of amplitude derivative xue@1: xue@1: No return value. xue@1: */ xue@1: 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) xue@1: { xue@1: BasicAnalyzer(fs, as, phs, das, x, Count, Wid, Offst, ref, reserved, LogA); xue@1: AdditiveUpdate(fs, as, phs, das, x, Count, Wid, Offst, BasicAnalyzer, reserved, LogA); xue@1: }//AdditiveAnalyzer xue@1: Chris@5: /** xue@1: function MultiplicativeUpdate: multiplicative reestimation of time-varying sinusoid xue@1: xue@1: In: x[Count]: waveform data xue@1: Wid, Offst: frame size and hop xue@1: fs[Count], as[Count], phs[Count]: initial estimate of sinusoid parameters xue@1: das[Count]: initial estimate of amplitude derivative xue@1: BasicAnalyzer: pointer to a sinusoid analyzer xue@1: LogA: indicates if amplitudes are interpolated at cubic spline or exponential cubic spline xue@1: Out: fs[Count], as[Count], phs[Count], das[Count]: estimates after additive update xue@1: xue@1: No return value. xue@1: */ xue@1: void MultiplicativeUpdate(double* fs, double* as, double* phs, double* das, cdouble* x, int Count, int Wid, int Offst, TBasicAnalyzer BasicAnalyzer, int reserved, bool LogA) xue@1: { xue@1: int HWid=Wid/2; xue@1: cdouble *y=new cdouble[Count]; xue@1: double *lf=new double[Count*8], *la=&lf[Count], *lp=&lf[Count*2], *lda=&lf[Count*3], xue@1: *lf2=&lf[Count*4], *la2=&lf2[Count], *lp2=&lf2[Count*2], *lda2=&lf2[Count*3]; xue@1: __int16 *lref=new __int16[Count]; xue@1: xue@1: for (int i=0; i0.5){} xue@1: } xue@1: xue@1: delete[] y; delete[] lf; delete[] lref; xue@1: }//MultiplicativeUpdate xue@1: Chris@5: /** xue@1: function MultiplicativeAnalyzer: sinusoid analyzer with one multiplicative update xue@1: xue@1: In: x[Count]: waveform data xue@1: Wid, Offst: frame size and hop size xue@1: BasicAnalyzer: pointer to a sinusoid analyzer xue@1: ref[Count]: reference frequencies, in bins, used by BasicAnalyzer xue@1: BasicAnalyzer: pointer to a sinusoid analyzer xue@1: LogA: indicates if amplitudes are interpolated at cubic spline or exponential cubic spline xue@1: Out: fs[Count], as[Count], phs[Count]: sinusoid parameter estimates xue@1: das[Count]: estimate of amplitude derivative xue@1: xue@1: No return value. xue@1: */ xue@1: 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) xue@1: { xue@1: BasicAnalyzer(fs, as, phs, das, x, Count, Wid, Offst, ref, reserved, LogA); xue@1: MultiplicativeUpdate(fs, as, phs, das, x, Count, Wid, Offst, BasicAnalyzer, reserved); xue@1: }//MultiplicativeAnalyzer xue@1: xue@1: /* xue@1: This is an earlier version of the multiplicative method without using a user-provided BasicAnalyzer. xue@1: This updates the sinusoid estimates at the selected consecutive FRAMES of x. Only frequency modulation xue@1: is included in the multiplier. The first frame (0) is centred at x[Wid/2]. fs, as, and phs are based xue@1: on frames rather than samples. Updates include frame frst, but not frame fren. xue@1: */ xue@1: void MultiplicativeUpdateF(double* fs, double* as, double* phs, __int16* x, int Fr, int frst, int fren, int Wid, int Offst) xue@1: { xue@1: int HWid=Wid/2; xue@1: xue@1: double *fa=new double[Fr*12], *fb=&fa[Fr], *fc=&fa[Fr*2], *fd=&fa[Fr*3], xue@1: *xs=&fa[Fr*8]; xue@1: for (int fr=0; frAmp[mpf]) mpf=k; xue@1: if (mpf>pf-4 && mpfabuf[fr]) fbuf[fr]=lf/lWid, abuf[fr]=la*2, pbuf[fr]=lp; xue@1: } xue@1: else xue@1: { xue@11: CFFTCW(xs, win, NULL, NULL, Log2(Wid), w, xc); xue@1: double lf=fbuf[fr]*Wid, la, lp; xue@1: LSESinusoid(lf, lf-3, lf+3, xc, Wid, 3, M, c, iH2, la, lp, 1e-3); xue@1: if (la*2>abuf[fr]) xue@1: fbuf[fr]=lf/Wid, abuf[fr]=la*2, pbuf[fr]=lp; xue@1: } xue@1: } xue@1: }//ReEstFreq xue@1: Chris@5: /** xue@1: function ReEstFreq_2: sinusoid reestimation by demodulating frequency. This is that same as ReEstFreq(...) xue@1: except that it calls Sinusoid(...) to synthesize the phase track used for demodulation and that it xue@1: does not allow variable window sizes for estimating demodulated sinusoid. xue@1: xue@1: In: x[Wid+Offst*(FrCount-1)]: waveform data xue@1: FrCount, Wid, Offst: frame count, frame size and hop size xue@1: fbuf[FrCount], ns[FrCount]: initial frequency estiamtes and their timing xue@1: win[Wid]: window function for LSE sinusoid estimation xue@1: M, c[], iH2: cosine-family window specification parameters, must be consistent with M, c, iH2 xue@1: w[Wid/2], xs[Wid], xc[Wid], f3[FrCount-1], f2[FrCount-1], f1[FrCount-1], f0[FrCount-1]: buffers xue@1: Out: fbuf[FrCount], abuf[FrCount], pbuf[FrCount]: reestimated frequencies, amplitudes and phase angles xue@1: xue@1: No return value. xue@1: */ xue@1: 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) xue@1: { xue@1: int hWid=Wid/2; xue@1: //reestimate using frequency track xue@1: CubicSpline(FrCount-1, f3, f2, f1, f0, ns, fbuf, 1, 1); xue@1: double *refcos=(double*)malloc8(sizeof(double)*Wid), *refsin=&refcos[hWid], ph=0, centralph; xue@1: xue@1: memset(f0, 0, sizeof(double)*FrCount); xue@1: xue@1: int N=Wid+Offst*(FrCount-1); xue@1: double* cosine=new double[N], *sine=new double[N]; xue@7: CosSin(&cosine[hWid], &sine[hWid], -hWid, 0, f3[0], f2[0], f1[0], f0[0], ph); xue@1: for (int fr=0; frabuf[fr]) xue@1: fbuf[fr]=lf/Wid, abuf[fr]=la*2, pbuf[fr]=lp+centralph; xue@1: } xue@1: }//ReEstFreq_2 xue@1: Chris@5: /** xue@1: function ReEstFreqAmp: sinusoid reestimation by demodulating frequency and amplitude. xue@1: xue@1: In: x[Wid+Offst*(FrCount-1)]: waveform data xue@1: FrCount, Wid, Offst: frame count, frame size and hop size xue@1: fbuf[FrCount], abuf[FrCount], ns[FrCount]: initial frequency and amplitude estiamtes and their xue@1: timing xue@1: win[Wid]: window function for estimating demodulated sinusoid xue@1: M, c[], iH2: cosine-family window specification parameters, must be consistent with win[] xue@1: Wids[FrCount]: specifies frame sizes for estimating individual frames of demodulated sinusoid, xue@1: optional xue@1: w[Wid/2], ps[Wid], xs[Wid], xc[Wid]: buffers xue@1: fa[FrCount-1], fb[FrCount-1], fc[FrCount-1], fd[FrCount-1]: buffers xue@1: aa[FrCount-1], ab[FrCount-1], ac[FrCount-1], ad[FrCount-1]: buffers xue@1: Out: fbuf[FrCount], abuf[FrCount], pbuf[FrCount]: reestimated frequencies, amplitudes and phase angles xue@1: xue@1: No return value. xue@1: */ xue@1: 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) xue@1: { xue@1: int hWid=Wid/2; xue@1: //reestimate using amplitude and frequency track xue@1: CubicSpline(FrCount-1, fa, fb, fc, fd, ns, fbuf, 0, 1); xue@1: CubicSpline(FrCount-1, aa, ab, ac, ad, ns, abuf, 0, 1); xue@1: for (int fr=0; fr=hWid)) tmp=1; xue@1: else if (as[hWid]>100*as[j]) tmp=100; xue@1: else tmp=as[hWid]/as[j]; xue@1: tmp=tmp*ldata[j]; xue@1: xs[j].x=tmp*cos(-ps[j]); xue@1: xs[j].y=tmp*sin(-ps[j]); xue@1: } xue@1: xue@1: if (Wids) xue@1: { xue@1: int lWid=Wids[fr], lhWid=Wids[fr]/2, lM; xue@1: SetTwiddleFactors(lWid, w); xue@1: double *lwin=NewWindow(wtHann, lWid), lc[4], liH2; xue@1: windowspec(wtHann, lWid, &lM, lc, &liH2); xue@11: CFFTCW(&xs[hWid-lhWid], lwin, NULL, NULL, Log2(lWid), w, xc); xue@1: delete[] lwin; xue@1: double lf=fbuf[fr]*lWid, la, lp; xue@1: LSESinusoid(lf, lf-3, lf+3, xc, lWid, 3, lM, lc, liH2, la, lp, 1e-3); xue@1: if (la*2>abuf[fr]) fbuf[fr]=lf/lWid, abuf[fr]=la*2, pbuf[fr]=lp; xue@1: } xue@1: else xue@1: { xue@11: CFFTCW(xs, win, NULL, NULL, Log2(Wid), w, xc); xue@1: double lf=fbuf[fr]*Wid, la, lp; xue@1: LSESinusoid(lf, lf-3, lf+3, xc, Wid, 3, M, c, iH2, la, lp, 1e-3); xue@1: if (la*2>abuf[fr]) fbuf[fr]=lf/Wid, abuf[fr]=la*2, pbuf[fr]=lp; xue@1: } xue@1: } xue@1: }//ReEstFreqAmp xue@1: Chris@5: /** xue@1: function Reestimate2: iterative demodulation method for sinusoid parameter reestimation. xue@1: xue@1: In: x[(FrCount-1)*Offst+Wid]: waveform data xue@1: FrCount, Wid, Offst: frame count, frame size and hop size xue@1: win[Wid]: window function xue@1: M, c[], iH2: cosine-family window specification parameters, must be consistent with win[] xue@1: Wids[FrCount]: specifies frame sizes for estimating individual frames of demodulated sinusoid, xue@1: optional xue@1: maxiter: maximal number of iterates xue@1: ae[FrCount], fe[FrCount], pe[FrCount]: initial amplitude, frequency and phase estimates xue@1: Out: aret[FrCount], fret[FrCount], pret[FrCount]: reestimated amplitudes, frequencies and phase angles xue@1: xue@1: Returns the number of unused iterates left of the total of maxiter. xue@1: */ xue@1: 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) xue@1: { xue@1: AllocateFFTBuffer(Wid, fft, w, xc); xue@1: double convep=1e-4, dif=0, lastdif=0; //convep is the hard-coded threshold that stops the iteration xue@1: int iter=1, hWid=Wid/2; xue@1: xue@1: double *ns=new double[FrCount*12], *as=new double[Wid*5]; xue@1: double *fbuf=&ns[FrCount], *abuf=&ns[FrCount*2], xue@1: *aa=&ns[FrCount*3], *ab=&ns[FrCount*4], *ac=&ns[FrCount*5], *ad=&ns[FrCount*6], xue@1: *fa=&ns[FrCount*7], *fb=&ns[FrCount*8], *fc=&ns[FrCount*9], *fd=&ns[FrCount*10], xue@1: *pbuf=&ns[FrCount*11]; xue@1: double *ps=&as[Wid]; xue@1: cdouble *xs=(cdouble*)&as[Wid*3]; xue@1: xue@1: memcpy(fbuf, fe, sizeof(double)*FrCount); xue@1: memcpy(abuf, ae, sizeof(double)*FrCount); xue@1: memcpy(pbuf, pe, sizeof(double)*FrCount); xue@1: for (int i=0; i1) lastdif=dif; xue@1: dif=0; xue@1: if (iter==1) xue@1: { xue@1: for (int fr=0; frfabs(ae[fr])) xue@1: dif+=fabs(fe[fr]-fbuf[fr])*Wid+fabs((ae[fr]-abuf[fr])/abuf[fr]); xue@1: else xue@1: dif+=fabs(fe[fr]-fbuf[fr])*Wid+fabs((ae[fr]-abuf[fr])/ae[fr]); xue@1: } xue@1: } xue@1: else xue@1: { xue@1: for (int fr=0; frfabs(aret[fr])) xue@1: dif+=fabs(fret[fr]-fbuf[fr])*Wid+fabs((aret[fr]-abuf[fr])/abuf[fr]); xue@1: else xue@1: dif+=fabs(fret[fr]-fbuf[fr])*Wid+fabs((aret[fr]-abuf[fr])/aret[fr]); xue@1: } xue@1: } xue@1: memcpy(fret, fbuf, sizeof(double)*FrCount); xue@1: memcpy(aret, abuf, sizeof(double)*FrCount); xue@1: dif/=FrCount; xue@1: if (fabs(dif)1 && fabs(dif-lastdif)hWid) m1=hWid; xue@1: for (int n=m0; n<=m1; n++) if (fft[n]>fft[m]) m=n; xue@1: cdouble Sw=0, S1w=0, S2w=0; xue@1: for (int n=0; n=0; kk--) thisX[kk]=-lastX[kk+1]+cdouble(0, omg)*lastX[kk]; xue@1: } xue@1: }//Xkw xue@1: Chris@5: /** xue@1: function Xkw: computes windowed spectrum of x and its derivatives up to order K at angular frequency xue@1: omg, from x and its derivatives using window w. xue@1: xue@1: In: x[K+1][Wid]: waveform data and its derivatives up to order K. xue@1: w[Wid]: window function xue@1: omg: angular frequency xue@1: Out: X[K+1]: windowed spectrum and its derivatives up to order K xue@1: xue@1: No return value. This function is for testing only. xue@1: */ xue@1: void Xkw(cdouble* X, int K, int Wid, double** x, double* w, double omg) xue@1: { xue@1: int hWid=Wid/2; xue@1: memset(X, 0, sizeof(cdouble)*(K+1)); xue@1: for (int i=0; i=0) xue@1: { xue@1: uind[up]=p; xue@1: ind[p]=up; xue@1: up++; xue@1: } xue@1: p++; xue@1: } xue@1: if (up!=Kr) throw(""); xue@1: } xue@1: xue@1: cdouble* Skw=new cdouble[M]; xue@1: Xkw(Skw, Kc, Wid, s, win, omg); xue@1: xue@1: double* x=new double[Wid]; xue@1: cdouble** Allocate2(cdouble, M, Kc, Smkw); xue@1: for (int m=1; m=0) //the real part being unknown xue@1: { xue@1: A[2*k][lind]=Smkw[m+1][k].x; xue@1: A[2*k+1][lind]=Smkw[m+1][k].y; xue@1: } xue@1: if ((lind=ind[2*m+1])>=0) //the imag part being unknown xue@1: { xue@1: A[2*k+1][lind]=Smkw[m+1][k].x; xue@1: A[2*k][lind]=-Smkw[m+1][k].y; xue@1: } xue@1: } xue@1: } xue@1: xue@1: bool dropeq=(2*Kc-1==Kr); xue@1: if (dropeq) xue@1: { xue@1: Allocate2(double, Kr+2, Kr, AA); xue@1: bb=AA[Kr], pqpq=AA[Kr+1]; xue@1: memcpy(AA[0], A[0], sizeof(double)*Kr*(Kr-1)); xue@1: memcpy(AA[Kr-1], A[Kr], sizeof(double)*Kr); xue@1: memcpy(bb, b, sizeof(double)*(Kr-1)); xue@1: bb[Kr-1]=((double*)(&Skw[1]))[Kr]; xue@1: } xue@1: xue@1: double det; xue@1: GECP(Kr, pq, A, b, &det); xue@1: if (dropeq) xue@1: { xue@1: double det2; xue@1: GECP(Kr, pqpq, AA, bb, &det2); xue@1: if (fabs(det2)>fabs(det)) memcpy(pq, pqpq, sizeof(double)*Kr); xue@1: DeAlloc2(AA); xue@1: } xue@1: memset(&r[1], 0, sizeof(double)*M1*2); xue@1: for (int k=0; k=0){uind[up]=p; ind[p]=up; up++;} p++;} if (up!=Kr) throw("");} xue@1: xue@1: //allocate buffer for linear system A(pq)=b xue@1: cdouble* Skw=new cdouble[Kc+1]; xue@1: double* x=new double[Wid]; xue@1: cdouble** Allocate2(cdouble, M, Kc, Smkw); xue@1: xue@1: Alloc2(2*Kc+2, 2*Kc, A); xue@1: double *b=A[2*Kc], *pq=A[2*Kc+1]; xue@1: xue@1: Xkw(Skw, Kc, Wid, s, win, omg); xue@1: for (int m=1; m=0) xue@1: { xue@1: A[2*k][lind]=Smkw[m+1][k].x; xue@1: A[2*k+1][lind]=Smkw[m+1][k].y; xue@1: } xue@1: if ((lind=ind[2*m+1])>=0) xue@1: { xue@1: A[2*k+1][lind]=Smkw[m+1][k].x; xue@1: A[2*k][lind]=-Smkw[m+1][k].y; xue@1: } xue@1: } xue@1: } xue@1: xue@1: if (2*Kc==Kr) GECP(Kr, pq, A, b); xue@1: else LSLinear2(2*Kc, Kr, pq, A, b); xue@1: xue@1: memset(&r[1], 0, sizeof(double)*M1*2); xue@1: for (int k=0; k=0){uind[up]=p; ind[p]=up; up++;} p++;}} xue@1: xue@1: //allocate buffer for linear system A(pq)=b xue@1: cdouble* Skw=new cdouble[Kc+1], Skw00; xue@1: double* x=new double[Wid]; xue@1: cdouble** Allocate2(cdouble, M, Kc, Smkw); xue@1: xue@1: Alloc2(2*Fr*Kc, 2*Fr*Kc, A); xue@1: double *pq=new double[2*Fr*Kc], *b=new double[2*Fr*Kc]; xue@1: xue@1: for (int fr=0; fr=0) xue@1: { xue@1: A[2*fr*Kc+2*k][lind]=Smkw[m+1][k].x; xue@1: A[2*fr*Kc+2*k+1][lind]=Smkw[m+1][k].y; xue@1: } xue@1: if ((lind=ind[2*m+1])>=0) xue@1: { xue@1: A[2*fr*Kc+2*k+1][lind]=Smkw[m+1][k].x; xue@1: A[2*fr*Kc+2*k][lind]=-Smkw[m+1][k].y; xue@1: } xue@1: } xue@1: } xue@1: } xue@1: if (2*Fr*Kc==Kr) GECP(Kr, pq, A, b); xue@1: else LSLinear2(2*Fr*Kc, Kr, pq, A, b); xue@1: xue@1: memset(&r[1], 0, sizeof(double)*M1*2); xue@1: for (int k=0; kM_PI) xue@1: { xue@1: if (ph_1-ph0>0) ph_1-=M_PI*2; xue@1: else ph_1+=M_PI*2; xue@1: } xue@1: if (fabs(ph1-ph0)>M_PI) xue@1: { xue@1: if (ph1-ph0>0) ph1-=M_PI*2; xue@1: else ph1+=M_PI*2; xue@1: } xue@1: double b2=(ph1+ph_1)*0.5-ph0, b1=(ph1-ph_1)*0.5, b0=ph0; xue@1: ph=b0+b1*(df+b2*df); xue@1: //now we have the QI estimates xue@1: double uff=2*a2, vf=b1+2*b2*df, vff=2*b2; xue@1: double dfdp=Wid/(2*M_PI*res); xue@1: double upp=uff*dfdp*dfdp, vp=vf*dfdp, vpp=vff*dfdp*dfdp; xue@1: double p=-upp*0.5/(upp*upp+vpp*vpp); xue@1: double alf=-2*p*vp, beta=p*vpp/upp; xue@1: //*direct method xue@1: double beta_p=beta/p; xue@1: double feses=f-alf*beta/p /(2*M_PI)*Wid, xue@1: yeses=y-alf*alf*0.25/p+0.25*log(1+beta_p*beta_p), xue@1: pheses=ph+alf*alf*beta*0.25/p-0.5*atan(beta_p); //*/ xue@1: /*adapted method xue@1: double zt[]={0, 0.995354, 0.169257, 1.393056, 0.442406, -0.717980, -0.251620, 0.177511, 0.158120, -0.503299}; xue@1: double delt=res/Wid; double delt0=df*delt; xue@1: beta=zt[3]*beta+zt[4]*delt0*alf; xue@1: alf=(zt[1]+zt[2]*delt*delt)*alf; xue@1: double beta_p=beta/p; xue@1: double feses=f+zt[5]*alf*beta/p /(2*M_PI)*Wid, xue@1: yeses=y+zt[6]*alf*alf/p+zt[7]*log(1+beta_p*beta_p), xue@1: pheses=ph+zt[8]*alf*alf*beta/p+zt[9]*atan(beta_p); //*/ xue@1: f=feses/Wid, a=exp(yeses), ph=pheses, fslope=2*beta/2/M_PI, aesp=alf; xue@1: }//TFAS05 xue@1: Chris@5: /** xue@1: function TFAS05_enh: the Abe-Smith method 2005 enhanced by LSE amplitude and phase estimation xue@1: xue@1: In: data[Wid]: waveform data xue@1: w[Wid]: window function xue@1: res: resolution of frequency for QIFFT xue@1: Out: f, a, ph: frequency, amplitude and phase angle estimates xue@1: aesp, fslope: estimates of log amplitude and frequency derivatives xue@1: xue@1: No return value. xue@1: */ xue@1: void TFAS05_enh(double& f, double& t, double& a, double& ph, double& aesp, double& fslope, int Wid, double* data, double* w, double res) xue@1: { xue@1: TFAS05(f, t, a, ph, aesp, fslope, Wid, data, w, res); xue@1: double xr=0, xi=0, p, win2=0; xue@1: for (int n=0; n<=Wid; n++) xue@1: { xue@1: double ni=n-Wid/2, tmp=data[n]*w[n]*w[n];//*exp(-aesp*(n-Wid/2)); if (IsInfinite(tmp)) continue; xue@1: p=-2*M_PI*(f+0.5*fslope*ni)*ni; xue@1: xr+=tmp*cos(p); xue@1: xi+=tmp*sin(p); xue@1: win2+=w[n]*w[n]; xue@1: } xue@1: a=sqrt(xr*xr+xi*xi)/win2; xue@1: ph=(xr==0 && xi==0)?0:atan2(xi, xr); xue@1: }//TFAS05_enh xue@1: //version without returning aesp and fslope xue@1: void TFAS05_enh(double& f, double& t, double& a, double& ph, int Wid, double* data, double* w, double res) xue@1: { xue@1: double aesp, fslope; xue@1: TFAS05_enh(f, t, a, ph, aesp, fslope, Wid, data, w, res); xue@1: }//TFAS05_enh xue@1: xue@1: //--------------------------------------------------------------------------- Chris@5: /** xue@1: function DerivativeLSv_AmpPh: estimate the constant-term in the local derivative method. This is used xue@1: by the local derivative algorithm, whose implementation is found in the header file as templates. xue@1: xue@1: In: sv0: inner product , where s is the sinusoid being estimated. xue@1: integr_h[M][Wid]: M vectors containing samples of the integral of basis functions h[M]. xue@1: v0[M]: a test function xue@1: lmd[M]: coefficients to h[M] xue@1: xue@1: Returns coefficient of integr_h[0]=1. xue@1: */ xue@1: cdouble DerivativeLSv_AmpPh(int Wid, int M, double** integr_h, cdouble* lmd, cdouble* v0, cdouble sv0) xue@1: { xue@1: cdouble e0=0; xue@1: for (int n=0; n=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];} xue@1: else{v[I-1][c]=u[I][c]*rot; dv[I-1][c]=du[I][c]*rot+jomg*v[I-1][c];} xue@1: } xue@1: }//setv xue@1: Chris@5: /** xue@1: function setvhalf: computes I half-size test functions v[I] by modulation u[I] to frequency f. xue@1: xue@1: In: u[I][hWid*2], du[I][Wid*2]: base-band test functions and their derivatives xue@1: f: carrier frequency xue@1: Out: v[I][hWid], dv[hWid]: half-size test functions and their derivatives xue@1: xue@1: No return value. xue@1: */void setvhalf(int I, int hWid, cdouble** v, cdouble** dv, double f, cdouble** u, cdouble** du) xue@1: { xue@1: double fbin=floor(f*hWid)/hWid; xue@1: double omg=fbin*2*M_PI; xue@1: cdouble jomg=cdouble(0, omg); xue@1: for (int c=0; c xue@1: cdouble*** Allocate3L(cdouble, L_1, I, N, srv, mlist); xue@1: cdouble** Allocate2L(cdouble, I, M, shv1, mlist); xue@1: cdouble** Allocate2L(cdouble, I, M, shv2, mlist); xue@1: xue@1: #ifdef ERROR_CHECK xue@1: cdouble dsv1[128], dsv2[128]; xue@1: #endif xue@1: for (int l=0; l over the lth frame xue@1: cdouble* ls=&s[l*T]; for (int i=0; i over the lth frame xue@1: cdouble *ls1=&s[l*T], *ls2=&s[l*T+T]; xue@1: for (int i=0; i=- xue@1: if (ds) xue@1: { xue@1: cdouble* lds=&ds[l*T]; xue@1: for (int i=0; i xue@1: //cdouble* ls=&s[l*T]; xue@1: //cdouble lsv2=Inner(2*T, ls, dv[i]); xue@1: dsv1[l*I+i]=lsv-sv[l][i]; //i.e. =-+dsv1[lI+i] xue@1: } xue@1: xue@1: //error check: srv[l]*pq= xue@1: for (int i=0; i over the lth frame xue@1: cdouble* ls=&s[0]; for (int i=0; i over the lth frame xue@1: for (int i=0; i=- xue@1: if (ds) xue@1: { xue@1: cdouble* lds=&ds[0]; xue@1: for (int i=0; i xue@1: //cdouble* ls=&s[l*T]; xue@1: //cdouble lsv2=Inner(2*T, ls, dv[i]); xue@1: dsv1[L_1*I+i]=lsv-sv[L_1][i]; //i.e. =-+dsv1[lI+i] xue@1: } xue@1: xue@1: //error check: srv[l]*pq= xue@1: for (int i=0; i over the lth frame xue@1: cdouble* ls=&s[(L-1)*T]; for (int i=0; i over the lth frame xue@1: for (int i=0; i=- xue@1: if (ds) xue@1: { xue@1: cdouble* lds=&ds[(L-1)*T]; xue@1: for (int i=0; i xue@1: //cdouble* ls=&s[l*T]; xue@1: //cdouble lsv2=Inner(2*T, ls, dv[i]); xue@1: dsv1[L_1*I+i]=lsv-sv[L_1][i]; //i.e. =-+dsv1[lI+i] xue@1: } xue@1: xue@1: //error check: srv[l]*pq= xue@1: for (int i=0; i xue@1: cdouble*** Allocate3L(cdouble, L_1, I, Np, srav, mlist); xue@1: cdouble*** srbv; xue@1: if (Np==Nq && B==A) srbv=srav; else {Allocate3L(cdouble, L_1, I, Nq, srbv, mlist);} //same model for amplitude and phase xue@1: cdouble** Allocate2L(cdouble, I, M, shv1, mlist); xue@1: cdouble** Allocate2L(cdouble, I, M, shv2, mlist); xue@1: xue@1: for (int l=0; l over the lth frame xue@1: cdouble* ls=&s[l*T]; for (int i=0; i over the lth frame xue@1: cdouble *ls1=&s[l*T], *ls2=&s[l*T+T]; xue@1: for (int i=0; i over the lth frame xue@1: cdouble* ls=&s[0]; for (int i=0; i over the lth frame xue@1: for (int i=0; i over the lth frame xue@1: cdouble* ls=&s[(L-1)*T]; for (int i=0; i over the lth frame xue@1: for (int i=0; iaita= xue@1: double** Allocate2L(double, L_1*I*2, Np+Nq, AM, mlist); xue@1: for (int l=0; lAdd(pq, 1); xue@1: double* b=new double[2*L_1*I]; for (int i=0; i equals -, dsv2[I] tests that *pq= xue@1: xue@1: */ xue@1: 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) xue@1: { xue@1: for (int i=0; i xue@1: //cdouble* ls=&s[l*T]; xue@1: dsv1[i]=lsv-svl[i]; //i.e. =-+dsv1[lI+i] xue@1: //sv[l][i]=lsv; xue@1: } xue@1: //error check: srv[l]*pq= xue@1: for (int i=0; i xue@1: */ xue@1: double testsv(int L, double* f, int T, cdouble* s, int I, cdouble** u, cdouble** du, int endmode) xue@1: { xue@1: cdouble** Allocate2(cdouble, I, T*2, v); xue@1: cdouble** Allocate2(cdouble, I, T*2, dv); xue@1: double ene=0; xue@1: for (int l=0; l over the lth frame xue@1: cdouble* ls=&s[l*T]; xue@1: for (int i=0; i xue@1: cdouble*** Allocate3L(cdouble, L_1, I, Np, srav, mlist); xue@1: cdouble*** srbv; xue@1: if (Np==Nq && B==DA) srbv=srav; else {Allocate3L(cdouble, L_1, I, Nq, srbv, mlist);} //same model for amplitude and phase xue@1: cdouble** Allocate2L(cdouble, I, M, shv1, mlist); xue@1: cdouble** Allocate2L(cdouble, I, M, shv2, mlist); xue@1: xue@1: #ifdef ERROR_CHECK xue@1: cdouble dsv1in[128], dsv2in[128]; xue@1: #endif xue@1: xue@1: for (int l=0; l over the lth frame xue@1: cdouble* ls=&s[l*T]; for (int i=0; i over the lth frame xue@1: cdouble *ls1=&s[l*T], *ls2=&s[l*T+T]; xue@1: for (int i=0; i=- and srv[l]*pq= xue@1: 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]); xue@1: #endif xue@1: } xue@1: L_1=L-1; xue@1: if (endmode==1 || endmode==3) xue@1: { xue@1: //v from u given f[l] xue@1: setvhalf(I, T, v, dv, (f[0]+f[1])/2, u, du); xue@1: //compute - over the lth frame xue@1: cdouble* ls=&s[0]; for (int i=0; i over the lth frame xue@1: for (int i=0; i=- and srv[l]*pq= xue@1: 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]); xue@1: #endif xue@1: L_1++; xue@1: } xue@1: if (endmode==2 || endmode==3) xue@1: { xue@1: //v from u given f[l] xue@1: setvhalf(I, T, v, dv, (f[L-1]+f[L])/2, u, du); xue@1: //compute - over the lth frame xue@1: cdouble* ls=&s[(L-1)*T]; for (int i=0; i over the lth frame xue@1: for (int i=0; i=- and srv[l]*pq= xue@1: 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]); xue@1: #endif xue@1: L_1++; xue@1: } xue@1: xue@1: //real implementation of aita= xue@1: double** Allocate2L(double, L_1*I*2, Np+Nq, AM, mlist); xue@1: for (int l=0; lAdd(pq, 1); xue@1: double* b=new double[2*L_1*I]; for (int i=0; iAdd(b, 1); xue@1: #ifdef ERROR_CHECK xue@1: //tests that AM is invariant to a constant shift of p xue@1: double errAM=0, errAM2=0, err1, err2; xue@1: for (int l=0; lAdd(edsin, 1); xue@1: errdsin=testds_pqA(Np, p, Nq, q, L, T, s, ds, M, h, dh, DA, B, edsin); xue@1: errdsvin=testsv(L, f, T, edsin, I, u, du, endmode); xue@1: } xue@1: #endif xue@1: Alloc2L(L_1*I*2, Np+Nq-1, Am, mlist); xue@1: for (int l=0; lAdd(edsout, 1); xue@1: errdsout=testds_pqA(Np, pq, Nq, &pq[Np], L, T, s, ds, M, h, dh, DA, B, edsout); xue@1: errdsvout=testsv(L, f, T, edsout, I, u, du, endmode); xue@1: } xue@1: #endif xue@1: memcpy(p, pq, sizeof(double)*Np); memcpy(q, &pq[Np], sizeof(double)*Nq); xue@1: xue@1: delete mlist; xue@1: }//DerivativePiecewise3 xue@1: xue@1: //initialization routines for the piecewise derivative method xue@1: Chris@5: /** xue@1: function seth: set h[M] to a series of power functions. xue@1: xue@1: In: M, T. xue@1: Out: h[M][T], where h[m] is power function of order m. xue@1: xue@1: No return value. h is allocated anew and must be freed by caller. xue@1: */ xue@1: void seth(int M, int T, double**& h, MList* mlist) xue@1: { xue@1: if (M<=0){h=0; return;} xue@1: Allocate2L(double, M, T, h, mlist); xue@1: double* hm=h[0]; for (int t=0; t1){dhm=dh[1]; for (int t=0; t0) li++; xue@1: } xue@1: } xue@1: DeAlloc2(wins); xue@1: }//setu xue@1: Chris@5: /** xue@1: function DerivativePiecewiseI: wrapper for DerivativePiecewise(), doing the initialization ,etc. xue@1: xue@1: In: L, T: number and length of pieces xue@1: s[LT]: waveform signal xue@1: ds[LT]: derivative of s[LT], used only when ERROR_CHECK is defined. xue@1: f[L+1]: reference frequencies at knots xue@1: M: polynomial degree of piecewise approximation xue@1: SpecifyA, ssmode: pointer to a function that fills A[L], and mode argument to call it xue@1: WinOrder: order(=vanishing moment) of window used for constructing test functions xue@1: I: number of test functions per frame. xue@1: endmode: set to 1 or 3 to apply half-size frame over [0, T], to 2 or 3 to apply over [LT-T, LT] xue@1: Out: aita[N]: independent coefficients, where N is specified by SpecifyA. xue@1: xue@1: No return vlue. xue@1: */ xue@1: void DerivativePiecewiseI(cdouble* aita, int L, double* f, int T, cdouble* s, int M, xue@1: void (*SpecifyA)(int L, int T, int M, int &N, double*** &A, MList* mlist, int mode), int ssmode, xue@1: int WinOrder, int I, int endmode, cdouble* ds) xue@1: { xue@1: MList* mlist=new MList; xue@1: cdouble **u, **du; xue@1: setu(I, 2*T, u, du, WinOrder, mlist); xue@1: xue@1: int N; double **h, ***A; xue@1: seth(M, T, h, mlist); xue@1: SpecifyA(L, T, M, N, A, mlist, ssmode); xue@1: xue@1: DerivativePiecewise(N, aita, L, f, T, s, A, M, h, I, u, du, endmode, ds); xue@1: delete mlist; xue@1: }//DerivativePiecewiseI xue@1: Chris@5: /** xue@1: function DerivativePiecewiseII: wrapper for DerivativePiecewise2(), doing the initialization ,etc. xue@1: This models the derivative of log ampltiude and frequency as separate piecewise polynomials, the first xue@1: specified by SpecifyA, the second by SpecifyB. xue@1: xue@1: In: L, T: number and length of pieces xue@1: s[LT]: waveform signal xue@1: ds[LT]: derivative of s[LT], used only when ERROR_CHECK is defined. xue@1: f[L+1]: reference frequencies at knots xue@1: M: polynomial degree of piecewise approximation xue@1: SpecifyA, ssAmode: pointer to a function that fills A[L], and mode argument to call it xue@1: SpecifyB, ssBmode: pointer to a function that fills B[L], and mode argument to call it xue@1: WinOrder: order(=vanishing moment) of window used for constructing test functions xue@1: I: number of test functions per frame. xue@1: endmode: set to 1 or 3 to apply half-size frame over [0, T], to 2 or 3 to apply over [LT-T, LT] xue@1: Out: p[Np], q[Nq]: independent coefficients, where Np and Nq are specified by SpecifyA and SpecifyB. xue@1: xue@1: No reutrn value. xue@1: */ xue@1: void DerivativePiecewiseII(double* p, double* q, int L, double* f, int T, cdouble* s, int M, xue@1: void (*SpecifyA)(int L, int T, int M, int &N, double*** &A, MList* mlist, int mode), int ssAmode, xue@1: void (*SpecifyB)(int L, int T, int M, int &N, double*** &B, MList* mlist, int mode), int ssBmode, xue@1: int WinOrder, int I, int endmode, cdouble* ds) xue@1: { xue@1: MList* mlist=new MList; xue@1: cdouble **u, **du; xue@1: setu(I, 2*T, u, du, WinOrder, mlist); xue@1: xue@1: int Np, Nq; xue@1: double **h, ***A, ***B; xue@1: seth(M, T, h, mlist); xue@1: SpecifyA(L, T, M, Np, A, mlist, ssAmode); xue@1: SpecifyB(L, T, M, Nq, B, mlist, ssBmode); xue@1: xue@1: DerivativePiecewise2(Np, p, Nq, q, L, f, T, s, A, B, M, h, I, u, du, endmode, ds); xue@1: xue@1: delete mlist; xue@1: }//DerivativePiecewiseII xue@1: Chris@5: /** xue@1: function DerivativePiecewiseIII: wrapper for DerivativePiecewise3(), doing the initialization ,etc. xue@1: Notice that this time the log amplitude, rather than its derivative, is modeled as a piecewise xue@1: polynomial specified by SpecifyA. xue@1: xue@1: In: L, T: number and length of pieces xue@1: s[LT]: waveform signal xue@1: ds[LT]: derivative of s[LT], used only when ERROR_CHECK is defined. xue@1: f[L+1]: reference frequencies at knots xue@1: M: polynomial degree of piecewise approximation xue@1: SpecifyA, ssAmode: pointer to a function that fills A[L], and mode argument to call it xue@1: SpecifyB, ssBmode: pointer to a function that fills B[L], and mode argument to call it xue@1: WinOrder: order(=vanishing moment) of window used for constructing test functions xue@1: I: number of test functions per frame. xue@1: endmode: set to 1 or 3 to apply half-size frame over [0, T], to 2 or 3 to apply over [LT-T, LT] xue@1: Out: p[Np], q[Nq]: independent coefficients, where Np and Nq are specified by SpecifyA and SpecifyB. xue@1: xue@1: No reutrn value. xue@1: */ xue@1: void DerivativePiecewiseIII(double* p, double* q, int L, double* f, int T, cdouble* s, int M, xue@1: void (*SpecifyA)(int L, int T, int M, int &N, double*** &A, MList* mlist, int mode), int ssAmode, xue@1: void (*SpecifyB)(int L, int T, int M, int &N, double*** &B, MList* mlist, int mode), int ssBmode, xue@1: int WinOrder, int I, int endmode, cdouble* ds) xue@1: { xue@1: MList* mlist=new MList; xue@1: int Np, Nq; xue@1: double **h, ***A, ***B, **dh=0; xue@1: cdouble **u, **du; xue@1: setu(I, T*2, u, du, WinOrder, mlist); xue@1: seth(M, T, h, mlist); xue@1: if (ds) setdh(M, T, dh, mlist); xue@1: SpecifyA(L, T, M, Np, A, mlist, ssAmode); xue@1: SpecifyB(L, T, M, Nq, B, mlist, ssBmode); xue@1: Alloc2L(M, M, DM, mlist); xue@1: memset(DM[0], 0, sizeof(double)*M*M); for (int m=0; mAdd(s2ph, 1); xue@1: double *phcor=new double[L+1]; mlist->Add(phcor, 1); xue@1: cdouble* lamda=new cdouble[M]; mlist->Add(lamda, 1); xue@1: double* lamdax=new double[M]; mlist->Add(lamdax, 1); xue@1: double* lamday=new double[M]; mlist->Add(lamday, 1); xue@1: { xue@1: double tmpph=0; xue@1: memset(s2ph, 0, sizeof(double)*(L+1)); xue@1: s2ph[0]=tmpph; xue@1: for (int l=0; lAdd(win, 1); xue@1: for (int l=1; lAdd(b, 1); mlist->Add(zet, 1); mlist->Add(dzet, 1); xue@1: double ihT[]={T, T/2.0*T, T/3.0*T*T, T/4.0*T*T*T}; xue@1: xue@1: Alloc2L(L, N, BB, mlist); xue@1: //prepare linear system (BB)(zet)=(b) xue@1: for (int l=0; l