# HG changeset patch # User Chris Cannam # Date 1286273080 -3600 # Node ID fc19d45615d1850bacc1a8b31db6a75663e1b7fd # Parent 6422640a802f01f9a5774896d67315b6490cd1f0 * Make all file names lower-case to avoid case ambiguity (some includes differed in case from the filenames they were trying to include). Also replace MinGW-specific mem.h with string.h diff -r 6422640a802f -r fc19d45615d1 Matrix.cpp --- a/Matrix.cpp Tue Oct 05 10:45:57 2010 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,2245 +0,0 @@ -//--------------------------------------------------------------------------- -#include -#include -#include "Matrix.h" -//--------------------------------------------------------------------------- -/* - function BalanceSim: applies a similarity transformation to matrix a so that a is "balanced". This is - used by various eigenvalue evaluation routines. - - In: matrix A[n][n] - Out: balanced matrix a - - No return value. -*/ -void BalanceSim(int n, double** A) -{ - if (n<2) return; - const int radix=2; - double sqrdx; - sqrdx=radix*radix; - bool finish=false; - while (!finish) - { - finish=true; - for (int i=0; iar) - { - ac/=radix; - sc/=sqrdx; - } - } - if ((sc+sr)/ac<0.95*s) - { - finish=false; - ar=1.0/ac; - for (int j=0; jAdd(Z, 2);} - int sizeN=sizeof(double)*N; - for (int m=0; mAdd(Z, 2);} - int sizeN=sizeof(cdouble)*N; - for (int m=0; mAdd(z, 1);} - memcpy(z, a, sizeof(double)*N); - return z; -}//Copy -cdouble* Copy(int N, cdouble* z, cdouble* a, MList* List) -{ - if (!z){z=new cdouble[N]; if (List) List->Add(z, 1);} - memcpy(z, a, sizeof(cdouble)*N); - return z; -}//Copy -//version without specifying pre-allocated z -double* Copy(int N, double* a, MList* List){return Copy(N, 0, a, List);} -cdouble* Copy(int N, cdouble* a, MList* List){return Copy(N, 0, a, List);} - -//--------------------------------------------------------------------------- -/* - function det: computes determinant by Gaussian elimination method with column pivoting - - In: matrix A[N][N] - - Returns det(A). On return content of matrix A is unchanged if mode=0. -*/ -double det(int N, double** A, int mode) -{ - int c, p, ip, *rp=new int[N]; for (int i=0; ifabs(A[rp[p]][i])) p=ip; ip++;} - if (A[rp[p]][i]==0) {result=0; goto ret;} - if (p!=i) {c=rp[i]; rp[i]=rp[p]; rp[p]=c; result=-result;} - for (int j=i+1; jmp) mp=mm, p=ip; ip++;} - if (mp==0) {result=0; goto ret;} - if (p!=i) {c=rp[i]; rp[i]=rp[p]; rp[p]=c;} - for (int j=i+1; j2) {l=m0-(m1-m0)*(m1-m0)/(m-2*m1+m0); delete[] y; return 0;} - k++; m0=m1; m1=m; - } - delete[] y; return 1; -}//EigPowerA - -//--------------------------------------------------------------------------- -/* - function EigPowerI: Inverse power method for solving the eigenvalue given an approximate non-zero - eigenvector. - - In: matrix A[N][N], approximate eigenvector x[N]. - Out: eigenvalue l, eigenvector x[N]. - - Returns 0 is successful. Content of matrix A is unchangd on return. Initial x[N] must not be zero. -*/ -int EigPowerI(int N, double& l, double* x, double** A, double ep, int maxiter) -{ - int sizeN=sizeof(double)*N; - double* y=new double[N]; MultiplyXy(N, N, y, A, x); - double q=Inner(N, x, y)/Inner(N, x, x), dt; - double** aa=new double*[N]; aa[0]=new double[N*N]; - for (int i=0; i=N) {delete[] rp; return 1;} - if (p!=i){c=rp[i]; rp[i]=rp[p]; rp[p]=c;} - for (int j=i+1; j=0; i--) - { - x[i]=b[rp[i]]; for (int j=i+1; jfabs(A[rp[p]][i])/s[rp[p]]) p=ip; ip++;} - if (A[rp[p]][i]==0) {delete[] s; delete[] rp; return 1;} - if (p!=i) {c=rp[i]; rp[i]=rp[p]; rp[p]=c;} - for (int j=i+1; j=0; i--) - { - x[i]=b[rp[i]]; for (int j=i+1; j=0; n--) - { - double xn=a[n]; - for (int m=n+1; m=0; n--) - { - for (int m=n+1; mA. - - In: matrix A[N][N] - Out: matrix A[N][N] - - Returns the determinant of the inverse matrix, 0 on failure. -*/ -double GICP(int N, double** A) -{ - int c, p, ip, *rp=new int[N]; for (int i=0; ifabs(A[rp[p]][i])) p=ip; ip++;} - if (A[rp[p]][i]==0) {delete[] rp; return 0;} - if (p!=i) {c=rp[i]; rp[i]=rp[p]; rp[p]=c; result=-result;} - result/=A[rp[i]][i]; - for (int j=i+1; j~A[rp[p]][i]) p=ip; ip++;} - if (A[rp[p]][i]==0) {delete[] rp; return 0;} - if (p!=i) {c=rp[i]; rp[i]=rp[p]; rp[p]=c; result=-result;} - result=result/(A[rp[i]][i]); - for (int j=i+1; jX. - - In: matrix A[N][N] - Out: matrix X[N][N] - - Returns the determinant of the inverse matrix, 0 on failure. -*/ -double GICP(int N, double** X, double** A) -{ - Copy(N, X, A); - return GICP(N, X); -}//GICP - -//--------------------------------------------------------------------------- -/* - function GILT: inv(lower trangular of A)->lower trangular of A - - In: matrix A[N][N] - Out: matrix A[N][N] - - Returns the determinant of the lower trangular of A -*/ -double GILT(int N, double** A) -{ - double result=1; - A[0][0]=1/A[0][0]; - for (int i=1; iupper trangular of A - - In: matrix A[N][N] - Out: matrix A[N][N] - - Returns the determinant of the upper trangular of A -*/ -double GIUT(int N, double** A) -{ - double result=1; - A[0][0]=1/A[0][0]; - for (int i=1; iA. - - In: matrix A[N][N] - Out: matrix A[N][N] - - Returns the determinant of the inverse matrix, 0 on failure. -*/ -double GISCP(int N, double** A) -{ - int c, p, ip, *rp=new int[N]; for (int i=0; ifabs(A[rp[p]][i]/s[rp[p]])) p=ip; ip++;} - if (A[rp[p]][i]==0) {delete[] s; delete[] rp; return 0;} - if (p!=i) {c=rp[i]; rp[i]=rp[p]; rp[p]=c; result=-result;} - result/=A[rp[i]][i]; - for (int j=i+1; jX. - - In: matrix A[N][N] - Out: matrix X[N][N] - - Returns the determinant of the inverse matrix, 0 on failure. -*/ -double GISCP(int N, double** X, double** A) -{ - Copy(N, X, A); - return GISCP(N, X); -}//GISCP - -//--------------------------------------------------------------------------- -/* - function GSI: Gaussian-Seidel iterative algorithm for solving linear system Ax=b. Breaks down if any - Aii=0, like the Jocobi method JI(...). - - Gaussian-Seidel iteration is x(k)=(D-L)^(-1)(Ux(k-1)+b), where D is diagonal, L is lower triangular, - U is upper triangular and A=L+D+U. - - In: matrix A[N][N], vector b[N], initial vector x0[N] - Out: vector x0[N] - - Returns 0 is successful. Contents of matrix A and vector b remain unchanged on return. -*/ -int GSI(int N, double* x0, double** A, double* b, double ep, int maxiter) -{ - double e, *x=new double[N]; - int k=0, sizeN=sizeof(double)*N; - while (k=maxiter) return 1; - return 0; -}//GSI - -//--------------------------------------------------------------------------- -/* - function Hessenb: reducing a square matrix A to upper Hessenberg form - - In: matrix A[N][N] - Out: matrix A[N][N], in upper Hessenberg form - - No return value. -*/ -void Hessenb(int N, double** A) -{ - double x, y; - for (int m=1; m fabs(x)) - { - x=A[j][m-1]; - i=j; - } - } - if (i!=m) - { - for (int j=m-1; j=1; i--) - { - int l=i-1; - double h=0, scale=0; - if (l>0) - { - for (int k=0; k<=l; k++) scale+=fabs(A[i][k]); - if (scale==0.0) sd[i]=A[i][l]; - else - { - for (int k=0; k<=l; k++) - { - A[i][k]/=scale; - h+=A[i][k]*A[i][k]; - } - double f=A[i][l]; - double g=(f>=0?-sqrt(h): sqrt(h)); - sd[i]=scale*g; - h-=f*g; - A[i][l]=f-g; - f=0; - for (int j=0; j<=l; j++) - { - A[j][i]=A[i][j]/h; - g=0; - for (int k=0; k<=j; k++) g+=A[j][k]*A[i][k]; - for (int k=j+1; k<=l; k++) g+=A[k][j]*A[i][k]; - sd[j]=g/h; - f+=sd[j]*A[i][j]; - } - double hh=f/(h+h); - for (int j=0; j<=l; j++) - { - f=A[i][j]; - sd[j]=g=sd[j]-hh*f; - for (int k=0; k<=j; k++) A[j][k]-=(f*sd[k]+g*A[i][k]); - } - } - } - else - sd[i]=A[i][l]; - d[i]=h; - } - - d[0]=sd[0]=0; - - for (int i=0; i=maxiter) return 1; - else return 0; -}//JI - -//--------------------------------------------------------------------------- -/* - function LDL: LDL' decomposition A=LDL', where L is lower triangular and D is diagonal identical l and - a allowed. - - The symmetric matrix A is positive definite iff A can be factorized as LDL', where L is lower - triangular with ones on its diagonal and D is diagonal with positive diagonal entries. - - If a symmetric matrix A can be reduced by Gaussian elimination without row interchanges, then it can - be factored into LDL', where L is lower triangular with ones on its diagonal and D is diagonal with - non-zero diagonal entries. - - In: matrix A[N][N] - Out: lower triangular matrix L[N][N], vector d[N] containing diagonal elements of D - - Returns 0 if successful. Content of matrix A is unchanged on return. -*/ -int LDL(int N, double** L, double* d, double** A) -{ - double* v=new double[N]; - - if (A[0][0]==0) {delete[] v; return 1;} - d[0]=A[0][0]; for (int j=1; j=N. Use of this function requires - the submatrix A[N][N] be invertible. - - In: matrix A[M][N], vector y[M], M>=N. - Out: vector x[N]. - - No return value. Contents of matrix A and vector y are unchanged on return. -*/ -void LSLinear2(int M, int N, double* x, double** A, double* y) -{ - double** A1=Copy(N, N, 0, A); - LU(N, x, A1, y); - if (M>N) - { - double** B=&A[N]; - double* Del=MultiplyXy(M-N, N, B, x); - MultiAdd(M-N, Del, Del, &y[N], -1); - double** A2=MultiplyXtX(N, N, A); - MultiplyXtX(N, M-N, A1, B); - MultiAdd(N, N, A2, A2, A1, 1); - double* b2=MultiplyXty(N, M-N, B, Del); - double* dx=new double[N]; - GESCP(N, dx, A2, b2); - MultiAdd(N, x, x, dx, -1); - delete[] dx; - delete[] Del; - delete[] b2; - DeAlloc2(A2); - } - DeAlloc2(A1); -}//LSLinear2 - -//--------------------------------------------------------------------------- -/* - function LU: LU decomposition A=LU, where L is lower triangular with diagonal entries 1 and U is upper - triangular. - - LU is possible if A can be reduced by Gaussian elimination without row interchanges. - - In: matrix A[N][N] - Out: matrices L[N][N] and U[N][N], subject to input values of L and U: - if L euqals NULL, L is not returned - if U equals NULL or A, U is returned in A, s.t. A is modified - if L equals A, L is returned in A, s.t. A is modified - if L equals U, L and U are returned in the same matrix - when L and U are returned in the same matrix, diagonal of L (all 1) is not returned - - Returns 0 if successful. -*/ -int LU(int N, double** L, double** U, double** A) -{ - double* diagl=new double[N]; - for (int i=0; i=0; i--) - { - x[i]/=A[i][i]; - for (int j=0; jb[i-j, j] - the main diagonal is b[0][0]~b[0][N-1] - the 1st upper subdiagonal is b[-1][1]~b[-1][N-1] - the 2nd upper subdiagonal is b[-2][2]~b[-2][N-1] - the 1st lower subdiagonal is b[1][0]~b[1][N-2] - the 2nd lower subdiagonal is b[2][0]~b[2][N-3] - - Out: L[N][N] and U[N][N], main diagonal of L being all 1 (probably), stored in a compact format in - b[-2:2][N]. - - Returns 0 if successful. -*/ -int LU_PD(int N, double** b) -{ - if (b[0][0]==0) return 1; - b[1][0]/=b[0][0], b[2][0]/=b[0][0]; - - //i=1, not to double b[*][i-2], b[-2][i] - b[0][1]-=b[1][0]*b[-1][1]; - if (b[0][1]==0) return 2; - b[-1][2]-=b[1][0]*b[-2][2]; - b[1][1]-=b[2][0]*b[-1][1]; - b[1][1]/=b[0][1]; - b[2][1]/=b[0][1]; - - for (int i=2; i=0; i--) - c[i]=(c[i]-b[-1][i+1]*c[i+1]-b[-2][i+2]*c[i+2])/b[0][i]; - } - return result; -}//LU_PD - -//--------------------------------------------------------------------------- -/* - function LUCP: LU decomposition A=LU with column pivoting - - In: matrix A[N][N] - Out: matrix A[N][N] now holding L and U by L_U[i][j]=A[ind[i]][j], where L_U - hosts L and U according to mode: - mode=0: L diag=abs(U diag), U diag as return - mode=1: L diag=1, U diag as return - mode=2: U diag=1, L diag as return - - Returns the determinant of A. -*/ -double LUCP(double **A, int N, int *ind, int &parity, int mode) -{ - double det=1; - parity=1; - - for (int i=0; ivmax) vmax=tmp; - if (vmax==0) { parity=0; goto deletenorm; } //det=0 at this point - norm[i]=1/vmax; - } - - int maxind; - for (int j=0; j=j - double tmp=A[i][j]; for (int k=0; k=vmax) maxind=i, vmax=tmp2; - } - if (vmax==0) { parity=0; goto deletenorm; } //pivot being zero - if (j!=maxind) - { - //do column pivoting: switching rows - for (int k=0; kAdd(z, 1);} \ - for (int m=0; mAdd(z, 1); \ - for (int m=0; m=maxiter) return 1; - double g=(d[l+1]-d[l])/(2*sd[l]); - double r=sqrt(g*g+1); - g=d[m]-d[l]+sd[l]/(g+(g>=0?r:-r)); - double s=1, c=1, p=0; - int i; - for (i=m-1; i>=l; i--) - { - double f=s*sd[i], b=c*sd[i]; - sd[i+1]=(r=sqrt(f*f+g*g)); - if (r==0) - { - d[i+1]-=p; - sd[m]=0; - break; - } - s=f/r, c=g/r; - g=d[i+1]-p; - r=(d[i]-g)*s+2.0*c*b; - p=s*r; - d[i+1]=g+p; - g=c*r-b; - for (int k=0; k=l) continue; - d[l]-=p; - sd[l]=g; - sd[m]=0.0; - } - } - while (m!=l); - } - return 0; -}//QL - -//--------------------------------------------------------------------------- -/* - function QR: nr version of QR method for solving upper Hessenberg system A. This is compatible with - Hessenb method. - - In: matrix A[N][N] - Out: vector ev[N] of eigenvalues - - Returns 0 on success. Content of matrix A is destroyed on return. -*/ -int QR(int N, double **A, cdouble* ev) -{ - int n=N, m, l, k, j, iter, i, mmin, maxiter=30; - double **a=A, z, y, x, w, v, u, t=0, s, r, q, p, a1=0; - for (i=0; i0?i-1:0; j=0) - { - iter=0; - do - { - for (l=n; l>0; l--) - { - s=fabs(a[l-1][l-1])+fabs(a[l][l]); - if (s==0) s=a1; - if (fabs(a[l][l-1])+s==s) {a[l][l-1]=0; break;} - } - x=a[n][n]; - if (l==n) {ev[n].x=x+t; ev[n--].y=0;} - else - { - y=a[n-1][n-1], w=a[n][n-1]*a[n-1][n]; - if (l==(n-1)) - { - p=0.5*(y-x); - q=p*p+w; - z=sqrt(fabs(q)); - x+=t; - if (q>=0) - { - z=p+(p>=0?z:-z); - ev[n-1].x=ev[n].x=x+z; - if (z) ev[n].x=x-w/z; - ev[n-1].y=ev[n].y=0; - } - else - { - ev[n-1].x=ev[n].x=x+p; - ev[n].y=z; ev[n-1].y=-z; - } - n-=2; - } - else - { - if (iter>=maxiter) return 1; - if (iter%10==9) - { - t+=x; - for (i=0; i<=n; i++) a[i][i]-=x; - s=fabs(a[n][n-1])+fabs(a[n-1][n-2]); - y=x=0.75*s; - w=-0.4375*s*s; - } - iter++; - for (m=n-2; m>=l; m--) - { - z=a[m][m]; - r=x-z; s=y-z; - p=(r*s-w)/a[m+1][m]+a[m][m+1]; q=a[m+1][m+1]-z-r-s; r=a[m+2][m+1]; - s=fabs(p)+fabs(q)+fabs(r); - p/=s; q/=s; r/=s; - if (m==l) break; - u=fabs(a[m][m-1])*(fabs(q)+fabs(r)); - v=fabs(p)*(fabs(a[m-1][m-1])+fabs(z)+fabs(a[m+1][m+1])); - if (u+v==v) break; - } - for (i=m+2; i<=n; i++) - { - a[i][i-2]=0; - if (i!=m+2) a[i][i-3]=0; - } - for (k=m; k<=n-1; k++) - { - if (k!=m) - { - p=a[k][k-1]; - q=a[k+1][k-1]; - r=0; - if (k!=n-1) r=a[k+2][k-1]; - x=fabs(p)+fabs(q)+fabs(r); - if (x!=0) p/=x, q/=x, r/=x; - } - if (p>=0) s=sqrt(p*p+q*q+r*r); - else s=-sqrt(p*p+q*q+r*r); - if (s!=0) - { - if (k==m) - { - if (l!=m) a[k][k-1]=-a[k][k-1]; - } - else a[k][k-1]=-s*x; - p+=s; - x=p/s; y=q/s; z=r/s; q/=p; r/=p; - for (j=k; j<=n; j++) - { - p=a[k][j]+q*a[k+1][j]; - if (k!=n-1) - { - p+=r*a[k+2][j]; - a[k+2][j]-=p*z; - } - a[k+1][j]-=p*y; a[k][j]-=p*x; - } - mmin=nl+1); - } - return 0; -}//QR - -/* - function QR_GS: QR decomposition A=QR using Gram-Schmidt method - - In: matrix A[M][N], M>=N - Out: Q[M][N], R[N][N] - - No return value. -*/ -void QR_GS(int M, int N, double** A, double** Q, double** R) -{ - double *u=new double[M]; - for (int n=0; n=N - Out: Q[M][M], R[M][N] - - No return value. -*/ -void QR_householder(int M, int N, double** A, double** Q, double** R) -{ - double *u=new double[M*3], *ur=&u[M], *qu=&u[M*2]; - for (int m=0; m0) alf=-alf; - for (int m=n; mAdd(z, 2);} - for (int m=0; m1) memset(A[1], 0, sizeof(double)*N*(N-1)); - for (int i=1; i=maxiter) return 1; - return 0; -}//SorI - -//--------------------------------------------------------------------------- -//Submatrix routines - -/* - function SetSubMatrix: copy matrix x[Y][X] into matrix z at (Y1, X1). - - In: matrix x[Y][X], matrix z with dimensions no less than [Y+Y1][X+X1] - Out: matrix z, updated. - - No return value. -*/ -void SetSubMatrix(double** z, double** x, int Y1, int Y, int X1, int X) -{ - for (int y=0; yAdd(z, 2);} - for (int y=0; yAdd(z, 1);} - memcpy(z, &x[X1], sizeof(cdouble)*X); - return z; -}//SubVector -//wrapper function -cdouble* SubVector(cdouble* x, int X1, int X, MList* List) -{ - return SubVector(0, x, X1, X, List); -}//SubVector - -//--------------------------------------------------------------------------- -/* - function transpose: matrix transpose: A'->A - - In: matrix a[N][N] - Out: matrix a[N][N] after transpose - - No return value. -*/ -void transpose(int N, double** a) -{ - double tmp; - for (int i=1; iZ - - In: matrix a[M][N] - Out: matrix z[N][M] - - Returns pointer to z. z is created anew if z=0 is specifid on start. -*/ -double** transpose(int N, int M, double** ta, double** a, MList* List) -{ - if (!ta) {Allocate2(double, N, M, ta); if (List) List->Add(ta, 2);} - for (int n=0; nAdd(P, 2);} - int sizeN=sizeof(double)*N; - for (int i=0; iAdd(P, 2); - return P; -}//Unitary -//wrapper functions -double** Unitary(int N, double* x, double* y, MList* List){return Unitary(N, 0, x, y, List);} -cdouble** Unitary(int N, cdouble* x, cdouble* y, MList* List){return Unitary(N, 0, x, y, List);} - - - diff -r 6422640a802f -r fc19d45615d1 Matrix.h --- a/Matrix.h Tue Oct 05 10:45:57 2010 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,407 +0,0 @@ -#ifndef MatrixH -#define MatrixH - -/* - Matrix.cpp - matrix operations. - - Matrices are accessed by double pointers as MATRIX[Y][X], where Y is the row index. -*/ - -#include "xcomplex.h" -#include "arrayalloc.h" - -//--Similar balance---------------------------------------------------------- -void BalanceSim(int n, double** A); - -//--Choleski factorization--------------------------------------------------- -int Choleski(int N, double** L, double** A); - -//--matrix copy-------------------------------------------------------------- -double** Copy(int M, int N, double** Z, double** A, MList* List=0); - double** Copy(int M, int N, double** A, MList* List=0); - double** Copy(int N, double** Z, double ** A, MList* List=0); - double** Copy(int N, double ** A, MList* List=0); -cdouble** Copy(int M, int N, cdouble** Z, cdouble** A, MList* List=0); - cdouble** Copy(int M, int N, cdouble** A, MList* List=0); - cdouble** Copy(int N, cdouble** Z, cdouble** A, MList* List=0); - cdouble** Copy(int N, cdouble** A, MList* List=0); -double* Copy(int N, double* z, double* a, MList* List=0); - double* Copy(int N, double* a, MList* List=0); -cdouble* Copy(int N, cdouble* z, cdouble* a, MList* List=0); - cdouble* Copy(int N, cdouble* a, MList* List=0); - -//--matrix determinant calculation------------------------------------------- -double det(int N, double** A, int mode=0); -cdouble det(int N, cdouble** A, int mode=0); - -//--power methods for solving eigenproblems---------------------------------- -int EigPower(int N, double& l, double* x, double** A, double ep=1e-6, int maxiter=50); -int EigPowerA(int N, double& l, double* x, double** A, double ep=1e-6, int maxiter=50); -int EigPowerI(int N, double& l, double* x, double** A, double ep=1e-6, int maxiter=50); -int EigPowerS(int N, double& l, double* x, double** A, double ep=1e-6, int maxiter=50); -int EigPowerWielandt(int N, double& m, double* u, double l, double* v, double** A, double ep=1e-06, int maxiter=50); -int EigenValues(int N, double** A, cdouble* ev); -int EigSym(int N, double** A, double* d, double** Q); - -//--Gaussian elimination for solving linear systems-------------------------- -int GEB(int N, double* x, double** A, double* b); -int GESCP(int N, double* x, double** A, double*b); -void GExL(int N, double* x, double** L, double* a); -void GExLAdd(int N, double* x, double** L, double* a); -void GExL1(int N, double* x, double** L, double a); -void GExL1Add(int N, double* x, double** L, double a); - -/* - template GECP: Gaussian elimination with maximal column pivoting for solving linear system Ax=b - - In: matrix A[N][N], vector b[N] - Out: vector x[N] - - Returns 0 if successful. Contents of matrix A and vector b are destroyed on return. -*/ -templateint GECP(int N, T* x, Ta** A, T *b, Ta* logdet=0) -{ - if (logdet) *logdet=1E-302; int c, p, ip, *rp=new int[N]; for (int i=0; ifabs(A[rp[p]][i])) p=ip; ip++;} - if (A[rp[p]][i]==0) {delete[] rp; return 1;} - if (p!=i) {c=rp[i]; rp[i]=rp[p]; rp[p]=c;} - for (int j=i+1; j=0; i--) - { - x[i]=b[rp[i]]; for (int j=i+1; j - - In: vectors x[N], w[N] and y[N] - - Returns inner product of xw and y. -*/ -templatecdouble Inner(int N, Tx* x, Tw* w, cdouble* y) -{ - cdouble result=0; - for (int i=0; icdouble Inner(int N, Tx* x, Tw* w, double* y) -{ - cdouble result=0; - for (int i=0; i=N. - - In: matrix A[M][N], vector y[M] - Out: vector x[N] - - Returns the log determinant of AtA. Contents of matrix A and vector y are unchanged on return. -*/ -template T LSLinear(int M, int N, T* x, T** A, T* y) -{ - MList* mlist=new MList; - T** AtA=MultiplyXtX(N, M, A, mlist); - T* Aty=MultiplyXty(N, M, A, y, mlist); - T result; GECP(N, x, AtA, Aty, &result); - delete mlist; - return result; -}//LSLinear - -//--2-stage Least-square solution of overdetermined linear system------------ -void LSLinear2(int M, int N, double* x, double** A, double* y); - -//--LU factorization of a non-singular matrix-------------------------------- -int LU_Direct(int mode, int N, double* diag, double** a); -int LU(int N, double** l, double** u, double** a); void LU_DiagL(int N, double** l, double* diagl, double** u, double** a); -int LU_PD(int N, double** b); -int LU_PD(int N, double** b, double* c); -double LUCP(double **a, int N, int *ind, int& parity, int mode=1); - -//--LU factorization method for solving a linear system---------------------- -void LU(int N, double* x, double** A, double* y, int* ind=0); - -//--find maximum of vector--------------------------------------------------- -int maxind(double* data, int from, int to); - -//--matrix linear combination------------------------------------------------ -/* - template MultiAdd: matrix linear combination Z=X+aY - - In: matrices X[M][N], Y[M][N], scalar a - Out: matrix Z[M][N] - - Returns pointer to Z. Z is created anew if Z=0 is specified on start. -*/ -template Tz** MultiAdd(int M, int N, Tz** Z, Tx** X, Ty** Y, Ta a, MList* List=0) -{ - if (!Z){Allocate2(Tz, M, N, Z); if (List) List->Add(Z, 2);} - for (int i=0; i Tz* MultiAdd(int N, Tz* z, Tx* x, Ty* y, Ta a, MList* List=0) -{ - if (!z){z=new Tz[N]; if (List) List->Add(z, 1);} - for (int i=0; i Tx* MultiAdd(int N, Tx* x, Ty* y, Ta a, MList* List=0) -{ - return MultiAdd(N, (Tx*)0, x, y, a, List); -}//MultiAdd - -//--matrix multiplication by constant---------------------------------------- -/* - template Multiply: matrix-constant multiplication Z=aX - - In: matrix X[M][N], scalar a - Out: matrix Z[M][N] - - Returns pointer to Z. Z is created anew if Z=0 is specified on start. -*/ -template Tz** Multiply(int M, int N, Tz** Z, Tx** X, Ta a, MList* List=0) -{ - if (!Z){Allocate2(Tz, M, N, Z); if (List) List->Add(Z, 2);} - for (int i=0; i Tz* Multiply(int N, Tz* z, Tx* x, Ta a, MList* List=0) -{ - if (!z){z=new Tz[N]; if (List) List->Add(z, 1);} - for (int i=0; iTx* Multiply(int N, Tx* x, Ta a, MList* List=0) -{ - return Multiply(N, (Tx*)0, x, a, List); -}//Multiply - -//--matrix multiplication operations----------------------------------------- -/* - macro Multiply_full: matrix-matrix multiplication z=xy and multiplication-accumulation z=z+xy. - - Each expansion of the macro defines three function templates; two are named $MULTIPLY and do matrix - multiplication only; one is named $MULTIADD and accumulates the multiplicated result on top of a - specified matrix. One of the two $MULTIPLY functions allows using a pre-allocated matrix to accept - the matrix product, while the other directly allocates a new matrix and returns the pointer. - - Functions are named after their exact functions. For example, MultiplyXYc multiplies matrix X with - the complex conjugate of matrix Y, where postfix "c" attched to Y stands for conjugate. Likewise, - the postfix "t" stands for transpose, and "h" stnads for Hermitian (conjugate transpose). - - Three dimension arguments are needed by each function template. The first and last of the three are - the number of rows and columns, respectively, of the product (output) matrix. The middle one is the - "other", common dimension of both multiplier matrices. -*/ -#define Multiply_full(MULTIPLY, MULTIADD, xx, yy) \ - templateTx** MULTIPLY(int N, int M, int K, Tx** z, Tx** x, Ty** y, MList* List=0){ \ - if (!z) {Allocate2(Tx, N, K, z); if (List) List->Add(z, 2);} \ - for (int n=0; nTx** MULTIPLY(int N, int M, int K, Tx** x, Ty** y, MList* List=0){ \ - Tx** Allocate2(Tx, N, K, z); if (List) List->Add(z, 2); \ - for (int n=0; nvoid MULTIADD(int N, int M, int K, Tx** z, Tx** x, Ty** y){ \ - for (int n=0; nT** MULTIPLY(int N, T** z, T** x, T** y, MList* List=0){ \ - if (!z){Allocate2(T, N, N, z); if (List) List->Add(z, 2);} \ - if (z!=x) MULTIPLY(N, N, N, z, x, y); else{ \ - T* tmp=new T[N]; int sizeN=sizeof(T)*N; for (int i=0; iT** MULTIPLY(int N, T** x, T** y, MList* List=0){return MULTIPLY(N, N, N, x, y, List);}\ - templatevoid MULTIADD(int N, T** z, T** x, T** y){MULTIADD(N, N, N, z, x, y);} -Multiply_square(MultiplyXY, MultiAddXY) - -/* - macro Multiply_xx: matrix self multiplication z=xx and self-multiplication-accumulation z=z+xx. - - Each expansion of the macro defines three function templates; two are named $MULTIPLY and do matrix - multiplication only; one is named $MULTIADD and accumulates the multiplicated result on top of a - specified matrix. One of the two $MULTIPLY functions allows using a pre-allocated matrix to accept - the matrix product, while the other directly allocates a new matrix and returns the pointer. -*/ -#define Multiply_xx(MULTIPLY, MULTIADD, xx1, xx2, zzt) \ - templateT** MULTIPLY(int M, int N, T** z, T** x, MList* List=0){ \ - if (!z){Allocate2(T, M, M, z); if (List) List->Add(z, 2);} \ - for (int m=0; mT** MULTIPLY(int M, int N, T ** x, MList* List=0){ \ - T** Allocate2(T, M, M, z); if (List) List->Add(z, 2); \ - for (int m=0; mvoid MULTIADD(int M, int N, T** z, T** x){ \ - for (int m=0; m -#include -#include "QuickSpec.h" - - -//--------------------------------------------------------------------------- -/* - method TQuickSpectrogram::TQuickSpectrogram: - - In: AParent: pointer argument for calling G, if G is specified - AnId: integer argument for calling G, if G is specified - G: pointer to a function that supplies buffers used for FFT, 0 by default - Ausex: set if complete complex spectrogram is to be buffered and accessible - Auseph: set if phase spectrogram is to be buffered and accessible -*/ -__fastcall TQuickSpectrogram::TQuickSpectrogram(void* AParent, int AnId, bool Ausex, bool Auseph, GetBuf G) -{ - memset(this, 0, sizeof(TQuickSpectrogram)); - Parent=AParent; - Id=AnId; - usex=Ausex; - useph=Auseph; - GetFFTBuffers=G; - BufferSize=QSpec_BufferSize; - fwt=wtRectangle; - Wid=1024; - Offst=512; -}//TQuickSpectrogram - -//TQuickSpectrogram::~TQuickSpectrogram -__fastcall TQuickSpectrogram::~TQuickSpectrogram() -{ - FreeBuffers(); - free8(fw); - free8(fwin); - free(fhbi); -}//~TQuickSpectrogram - -//--------------------------------------------------------------------------- -/* - method TQuickSpectrogram::A: accesses amplitude spectrogram by frame - - In: fr: frame index, 0-based - - Returns pointer to amplitude spectrum of the fr'th frame, NULL if N/A -*/ -QSPEC_FORMAT* __fastcall TQuickSpectrogram::A(int fr) -{ - if (Capacity==0) SetFrCapacity((DataLength-Wid)/Offst+2); - if (fr<0 || fr>=Capacity) return NULL; - if (Frame[fr]<0 || !Valid[fr]) CalculateSpectrum(fr); - return fA[Frame[fr]]; -}//A - -//--------------------------------------------------------------------------- -/* - method TQuickSpectrogram::AddBuffer: increases internal buffer by BufferSize frames. Allocated buffers - beyond Capacity frames will not be indexed or used by TQuickSpectrogram. -*/ -void TQuickSpectrogram::AddBuffer() -{ - int base=1, Dim=Wid/2+1; - if (usex) base+=2; - if (useph) base+=1; - QSPEC_FORMAT* newbuffer=(QSPEC_FORMAT*)malloc(sizeof(QSPEC_FORMAT)*Dim*BufferSize*base); - int fr0=BufferCount*BufferSize; - for (int i=0; i*)&newbuffer[(BufferSize+i*2)*Dim], base+=2; - if (useph) fPh[fr]=&newbuffer[(BufferSize*base+i)*Dim]; - } - else break; - } - BufferCount++; -}//AddBuffer - -/* - method TQuickSpectrogram::AddBuffer: increase internal buffer by a multiple of BufferSize so that - it will be enough to host another AddFrCount frames. -*/ -void TQuickSpectrogram::AddBuffer(int AddFrCount) -{ - while (FrCount+AddFrCount>BufferSize*BufferCount) AddBuffer(); -}//AddBuffer - -//--------------------------------------------------------------------------- -/* - function IntToDouble: copy content of integer array to double array - - In: in: pointer to integer array - BytesPerSample: number of bytes each integer takes - Count: size of integer array, in integers - Out: vector out[Count]. - - No return value. -*/ -void IntToDouble(double* out, void* in, int BytesPerSample, int Count) -{ - if (BytesPerSample==1){unsigned char* in8=(unsigned char*)in; for (int k=0; k* lX=usex?fSpec[realfr]:NULL; - //choose the buffer actually used for FFT - use lX if it is specified as complex double array - //because it saves unnecessary data copying operations - cdouble *lx=(usex && sizeof(QSPEC_FORMAT)==sizeof(double))?(cdouble*)lX:x; - - //Actual FFT - if (fr*Offst+Wid<=DataLength) - ::CalculateSpectrum(&((char*)Data)[fr*Offst*BytesPerSample], BytesPerSample, win, fA[realfr], lph, Wid, w, lx, hbi); - else - ::CalculateSpectrum(&((char*)Data)[fr*Offst*BytesPerSample], BytesPerSample, win, fA[realfr], lph, Wid, DataLength-fr*Offst, w, x, hbi); - - //optional data copy from x to lX - if (usex && lx==x) for (int i=0; i=Capacity) fr2=Capacity-1; - for (int fr=fr1; fr<=fr2; fr++) if (Frame[fr]>=0) Valid[fr]=false, result++; - } - return result; -}//Invalidate - -//--------------------------------------------------------------------------- -/* - method TQuickSpectrogram::Ph: accesses phase spectrogram by frame - - In: fr: frame index, 0-based - - Returns pointer to phase spectrum of the fr'th frame, NULL if N/A -*/ -QSPEC_FORMAT* __fastcall TQuickSpectrogram::Ph(int fr) -{ - if (Capacity==0) SetFrCapacity((DataLength-Wid)/Offst+2); - if (fr<0 || fr>=Capacity) return NULL; - if (Frame[fr]<0 || !Valid[fr]) CalculateSpectrum(fr); - return fPh[Frame[fr]]; -}//Ph - -//--------------------------------------------------------------------------- -/* - method TQuickSpectrogram::SetFrCapacity: sets the capacity, i.e. the maximal number of frames handled - by this TQuickSpectrogram. - - In: AnFrCapacity: the new Capacity, in frames - - This method should not be called to set Capacity to a smaller value. -*/ -void TQuickSpectrogram::SetFrCapacity(int AnFrCapacity) -{ - //adjusting the size of index and validity arrays - Frame=(int*)realloc(Frame, sizeof(int)*AnFrCapacity); - Valid=(int*)realloc(Valid, sizeof(int)*AnFrCapacity); - - // - fA=(QSPEC_FORMAT**)realloc(fA, sizeof(QSPEC_FORMAT*)*AnFrCapacity); - if (usex) fSpec=(cmplx**)realloc(fSpec, sizeof(cmplx*)*AnFrCapacity); - if (useph) fPh=(QSPEC_FORMAT**)realloc(fPh, sizeof(QSPEC_FORMAT*)*AnFrCapacity); - if (AnFrCapacity>Capacity) - { - memset(&Frame[Capacity], 0xFF, sizeof(int)*(AnFrCapacity-Capacity)); - memset(&Valid[Capacity], 0x00, sizeof(int)*(AnFrCapacity-Capacity)); - - if (Capacity*)(&thisbuffer[(BufferSize+lfr*2)*Dim]), base+=2; - if (useph) fPh[fr]=&thisbuffer[(BufferSize*base+lfr)*Dim]; - } - else break; - } - } - } - Capacity=AnFrCapacity; -}//SetFrCapacity - -//--------------------------------------------------------------------------- -/* - method TQuickSpectrogram::Ph: accesses complex spectrogram by frame - - In: fr: frame index, 0-based - - Returns pointer to complex spectrum of the fr'th frame, NULL if N/A -*/ -cmplx* __fastcall TQuickSpectrogram::Spec(int fr) -{ - if (Capacity==0) SetFrCapacity((DataLength-Wid)/Offst+2); - if (fr<0 || fr>=Capacity) return NULL; - if (Frame[fr]<0 || !Valid[fr]) CalculateSpectrum(fr); - return fSpec[Frame[fr]]; -}//Spec - - diff -r 6422640a802f -r fc19d45615d1 QuickSpec.h --- a/QuickSpec.h Tue Oct 05 10:45:57 2010 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,158 +0,0 @@ -#ifndef QuickSpecH -#define QuickSpecH - -/* - QuickSpec.cpp - TQuickSpectrogram class - - TQuickSpectrogram implements a compute-on-request spectrogram class. Every time one frame of the - spectrogram is read from this class, it checks if the single-frame spectrogram has been computed - already, computes it if not, and return the pointer to the spectrum. - - Further reading: "A buffering technique for real-time spectrogram displaying.pdf" -*/ - - -#include -#include -#include "xcomplex.h" -#include "windowfunctions.h" -#include "fft.h" -//--------------------------------------------------------------------------- - -#define QSPEC_FORMAT float //default spectral data format -#define QSpec_BufferSize 1024 //default initial buffer size, in frames, of TQuickSpectrogram - - -/* - __int24 is a 24bit signed integer type and __pint24 is its pointer type. Although __int24* will also - return a pointer to an __int24 structure, operations based on __int24* may have unspecified results, - depending on structure alignments imposed by compiler. It is therefore necessary to have an explicit - pointer type __pint24 to enforce 24-bit data alighment. - - Using __int24: - When storage format is not a concern, __int24 can be used the same way as __int16 or __int32. However, - a default 32-bit compiler may fail to implement compact 24-bit alignment to entries of an __int24[] - array. If 24-bit alignment is desired, then always create the array dynamically with new[], which - returns a __pint24 type pointer. Assigning a __pint24 type pointer to __int24* type variable should - be avoided. -*/ - -#ifndef INT24 -#define INT24 -struct __int24; -struct __pint24 -{ - char* p; - __fastcall __pint24(){} - __fastcall __pint24(const void* ap){p=(char*)ap;} - __pint24& __fastcall operator=(const void* ap){p=(char*)ap; return *this;} - __int24& __fastcall operator*(){return *(__int24*)p;} - __int24& __fastcall operator[](int index){return *(__int24*)&p[3*index];} - __pint24 __fastcall operator++(int){__pint24 result=*this; p+=3; return result;} - __pint24& __fastcall operator++(){p+=3; return *this;} - __pint24 __fastcall operator--(int){__pint24 result=*this; p-=3; return result;} - __pint24& __fastcall operator--(){p-=3; return *this;} - __pint24& __fastcall operator+=(int a){p+=3*a; return *this;} - __pint24& __fastcall operator-=(int a){p-=3*a; return *this;} - __fastcall operator void*() const{return p;} -}; -struct __int24 -{ - __int16 loword; - __int8 hibyte; - __fastcall __int24(){} - __fastcall __int24(const __int32 a){loword=*(__int16*)&a; hibyte=((__int16*)&a)[1];} - __fastcall __int24(const double f){__int32 a=f; loword=*(__int16*)&a; hibyte=((__int16*)&a)[1];} - __int24& __fastcall operator=(const __int32 a){loword=*(__int16*)&a; hibyte=((__int16*)&a)[1]; return *this;} - __int24& __fastcall operator=(const double f){__int32 a=f; loword=*(__int16*)&a; hibyte=((__int16*)&a)[1]; return *this;} - __fastcall operator __int32() const{__int32 result; *(__int16*)&result=loword; ((__int16*)&result)[1]=hibyte; return result;} - __pint24 operator &(){return (__pint24)this;} - void* operator new[](size_t count){void* result=malloc(3*count); return result;} - void operator delete[](void* p){free(p);} -}; -#endif - -/* - TQuickSpectrogram is a spectrogram class the handles the computation and storage of a spectrogram. - - Using TQuickSpectrogram: - - TQuickSpectrogram provides read-only access to the spectrogram of a given waveform. The spectrogram - contains a sequence of windowed Fourier transforms, computed from uniformly placed frames. The 0th - frame starts at 0 (inclusive) and finishes at Wid (exclusive). Each spectrum has Wid/2+1 entries. - - Follow these steps: - 1. create a QuickSpectrogram, specifying usex and useph, and optionally, external buffer provide G - and its arguments Id and Parent; - 2. set Data, DataLength and BytesPerSample; - 3. set frame size and hop size Wid and Offst; - 4. if G is not specified, set window type (optional extra parameter) for computing spectra; - 5. access the spectrogram via A(fr), Spec(fr) (optional) and Ph(fr) (optional). - Steps 2~4 do not have to follow the given order. - - Call Invalidate() to notify the object of changes of waveform content. - Call FreeBuffers() to return the object to the initial state before step 2. -*/ - -typedef void (*GetBuf)(int Id, cdouble* &w, cdouble* &x, double* &win, int* &hbi, void* Parent); -class TQuickSpectrogram -{ - int BufferCount; //number of buffers in use - int BufferSize; //number of frames each additional buffer holds - int FrCount; //number of allocated frames - - //internal storage of spectrogram - QSPEC_FORMAT** fPh; //phase spectrogram, optional - QSPEC_FORMAT** fA; //amplitude spectrogram, compulsory - cmplx** fSpec; //complete complex spectrogram, optional - - //internal buffers (optional) for FFT - WindowType fwt; //type of window - int fWid; //size of window - int* fhbi; //half-size bit-inversed integer table - double fwdp; //additional parameter specifying window type - double* fwin; //internal window - cdouble* fw; //FFT twiddle factors - cdouble* fx; //FFT data buffer - - //x and ph create-time switch - bool usex; //set at create time if complex spectrogram is required - bool useph; //set at create time if phase spectrogram is required - - //internal methods - void AddBuffer(); - void AddBuffer(int AddFrCount); - void __fastcall CalculateSpectrum(int fr); - void SetFrCapacity(int AnFrCapacity); - -public: - //if specified, Parent is responsible to supply FFT buffers through GetFFTBuffers (optional) - int Id; //an identifier given at create time, used as argument for calling GetFFTBuffers() - void* Parent; //a pointer used as argument for calling GetFFTBuffers() - GetBuf GetFFTBuffers; //if specified, this supplies FFT buffers - - //index and validity arrays associated with internal storage - int Capacity; //size of $Frame[] and &Valid[], usually set to the total number of frames of the data - int* Frame; //indices to individual frames in internal storage - int* Valid; //validity tags to individual frames in internal storage - - WindowType WinType; //window type for computing spectrogram - double WinParam; //additional parameter specifying certain window types (Gaussian, Kaiser, etc.) - - void* Data; //pointer to waveform audio - int DataLength; //length of waveform audio, in samples - int BytesPerSample; //bytes per sample of waveform audio - - int Offst; //frame offset - int Wid; //frame size, the same as window size - - __fastcall TQuickSpectrogram(void* AParent, int AnId, bool Ausex, bool Auseph, GetBuf G); - __fastcall ~TQuickSpectrogram(); - - QSPEC_FORMAT* __fastcall A(int fr); //accesses amplitude spectrogram at frame fr - void FreeBuffers(); //discards all computed frames and free memory - int Invalidate(int From, int To); //discards computed frames - QSPEC_FORMAT* __fastcall Ph(int fr); //accesses phase spectrogram at frame fr - cmplx* __fastcall Spec(int fr); //accesses complex spectrogram at frame fr -}; -#endif diff -r 6422640a802f -r fc19d45615d1 SinEst.cpp --- a/SinEst.cpp Tue Oct 05 10:45:57 2010 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,3970 +0,0 @@ -//--------------------------------------------------------------------------- - -#include -#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 (k1K2) 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 (k1K2) 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 (k1K2) 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=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; lFr, 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; lFr, 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; kx=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; lFr, 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; lL, 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; lL, 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; lL, 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=p.N/2) p.k2=p.N/2-1; - tmp=IPWindow(lf, &p); - if (minp=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=p.N/2) p.k2=p.N/2-1; - tmp=IPWindow(lf, &p); - if (minp=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) - { - 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; frsdip), 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=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=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=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; i0 && 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; n0 && 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; k0 && 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; kx=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; kf1, 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; kf1, 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) 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; i6) 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; n0.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; i1) - { - 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; fr0.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; i0.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; frAmp[mpf]) mpf=k; - if (mpf>pf-4 && mpfabuf[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; frabuf[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=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; i1) lastdif=dif; - dif=0; - if (iter==1) - { - for (int fr=0; frfabs(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; frfabs(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)1 && fabs(dif-lastdif)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=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=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=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=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=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=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=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; kM_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 , 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=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 - 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 over the lth frame - cdouble* ls=&s[l*T]; for (int i=0; i over the lth frame - cdouble *ls1=&s[l*T], *ls2=&s[l*T+T]; - for (int i=0; i=- - if (ds) - { - cdouble* lds=&ds[l*T]; - for (int i=0; i - //cdouble* ls=&s[l*T]; - //cdouble lsv2=Inner(2*T, ls, dv[i]); - dsv1[l*I+i]=lsv-sv[l][i]; //i.e. =-+dsv1[lI+i] - } - - //error check: srv[l]*pq= - for (int i=0; i over the lth frame - cdouble* ls=&s[0]; for (int i=0; i over the lth frame - for (int i=0; i=- - if (ds) - { - cdouble* lds=&ds[0]; - for (int i=0; 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. =-+dsv1[lI+i] - } - - //error check: srv[l]*pq= - for (int i=0; i over the lth frame - cdouble* ls=&s[(L-1)*T]; for (int i=0; i over the lth frame - for (int i=0; i=- - if (ds) - { - cdouble* lds=&ds[(L-1)*T]; - for (int i=0; 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. =-+dsv1[lI+i] - } - - //error check: srv[l]*pq= - for (int i=0; i - 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 over the lth frame - cdouble* ls=&s[l*T]; for (int i=0; i over the lth frame - cdouble *ls1=&s[l*T], *ls2=&s[l*T+T]; - for (int i=0; i over the lth frame - cdouble* ls=&s[0]; for (int i=0; i over the lth frame - for (int i=0; i over the lth frame - cdouble* ls=&s[(L-1)*T]; for (int i=0; i over the lth frame - for (int i=0; iaita= - double** Allocate2L(double, L_1*I*2, Np+Nq, AM, mlist); - for (int l=0; lAdd(pq, 1); - double* b=new double[2*L_1*I]; for (int i=0; i equals -, dsv2[I] tests that *pq= - -*/ -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 - //cdouble* ls=&s[l*T]; - dsv1[i]=lsv-svl[i]; //i.e. =-+dsv1[lI+i] - //sv[l][i]=lsv; - } - //error check: srv[l]*pq= - for (int i=0; i -*/ -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 over the lth frame - cdouble* ls=&s[l*T]; - for (int i=0; i - 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 over the lth frame - cdouble* ls=&s[l*T]; for (int i=0; i over the lth frame - cdouble *ls1=&s[l*T], *ls2=&s[l*T+T]; - for (int i=0; i=- and srv[l]*pq= - 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 - over the lth frame - cdouble* ls=&s[0]; for (int i=0; i over the lth frame - for (int i=0; i=- and srv[l]*pq= - 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 - over the lth frame - cdouble* ls=&s[(L-1)*T]; for (int i=0; i over the lth frame - for (int i=0; i=- and srv[l]*pq= - 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 aita= - double** Allocate2L(double, L_1*I*2, Np+Nq, AM, mlist); - for (int l=0; lAdd(pq, 1); - double* b=new double[2*L_1*I]; for (int i=0; iAdd(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; lAdd(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; lAdd(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; t1){dhm=dh[1]; for (int t=0; t0) 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; mAdd(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; lAdd(win, 1); - for (int l=1; lAdd(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 -#include "xcomplex.h" -#include "arrayalloc.h" -#include "matrix.h" -#ifdef I -#undef I -#endif - -//--since function derivative------------------------------------------------ -double ddsincd_unn(double x, int N); -double dsincd_unn(double x, int N); - -//--window spectrum and derivatives------------------------------------------ -cdouble* Window(cdouble* x, double f, int N, int M, double* c, int K1, int K2); -void dWindow(cdouble* dx, cdouble* x, double f, int N, int M, double* c, int K1, int K2); -void ddWindow(cdouble* ddx, cdouble* dx, cdouble* x, double f, int N, int M, double* c, int K1, int K2); - -//--spectral projection routines--------------------------------------------- -cdouble IPWindowC(double f, cdouble* x, int N, int M, double* c, double iH2, int K1, int K2); - -double IPWindow(double f, cdouble* x, int N, int M, double* c, double iH2, int K1, int K2, bool returnamplitude); -double IPWindow(double f, void* params); -double ddIPWindow(double f, void* params); -double ddIPWindow(double f, cdouble* x, int N, int M, double* c, double iH2, int K1, int K2, double& dipwindow, double& ipwindow); - -double sIPWindow(double f, int L, cdouble** x, int N, int M, double* c, double iH2, int K1, int K2, cdouble* ej2ph=0); -double sIPWindow(double f, void* params); -double dsIPWindow(double f, int L, cdouble** x, int N, int M, double* c, double iH2, int K1, int K2, double& sip); -double dsIPWindow(double f, void* params); -double ddsIPWindow(double f, int L, cdouble** x, int N, int M, double* c, double iH2, int K1, int K2, double& dsip, double& sip); -double ddsIPWindow(double f, void* params); -double ddsIPWindow_unn(double f, cdouble* x, int N, int M, double* c, int K1, int K2, double& dsipwindow, double& sipwindow, cdouble* w_unn=0); - -double sIPWindowC(double f, int L, double offst_rel, cdouble** x, int N, int M, double* c, double iH2, int K1, int K2, cdouble* ej2ph=0); -double sIPWindowC(double f, void* params); -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); -double dsIPWindowC(double f, void* params); -double ddsIPWindowC(double f, int L, double offst_rel, cdouble** x, int N, int M, double* c, double iH2, int K1, int K2, double& dsip, double& sip); -double ddsIPWindowC(double f, void* params); - -//--least-square sinusoid estimation routines-------------------------------- -double LSESinusoid(cdouble* x, int N, double B, int M, double* c, double iH2, double& a, double& pp, double epf=1e-6); -void LSESinusoid(double& f, cdouble* x, int N, double B, int M, double* c, double iH2, double& a, double& pp, double epf=1e-6); -double LSESinusoid(int f1, int f2, cdouble* x, int N, double B, int M, double* c, double iH2, double& a, double& pp, double epf); -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); -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); - -//--multi-sinusoid spectral projection routines------------------------------ -void IPMulti(int I, double* f, cdouble* lmd, cdouble* x, int Wid, int K1, int K2, int M, double* c, double eps=0); -void IPMulti(int I, double* f, cdouble* lmd, cfloat* x, int Wid, int K1, int K2, int M, double* c, double eps=0, double* sens=0, double* r1=0); -void IPMultiSens(int I, double* f, int Wid, int K1, int K2, int M, double* c, double* sens, double eps=0); -double IPMulti(int I, double* f, cdouble* lmd, cdouble* x, int Wid, int M, double* c, double iH2, int B); -double IPMulti_Direct(int I, double* f, double* ph, double* a, cdouble* x, int Wid, int M, double* c, double iH2, int B); -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=0, double** Q=0); -cdouble* IPMulti(int I, int J, double* f, double* ph, double* a, cdouble* x, int Wid, int M, double* c, cdouble** wt=0, cdouble** Q=0, double** L=0, MList* RetList=0); - -//--dual-sinusoid spectral projection routines------------------------------- -double WindowDuo(double df, int N, double* d, int M, cdouble* w); -double ddWindowDuo(double df, int N, double* d, int M, double& dwindow, double& window, cdouble* w); -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); -double sIPWindowDuo(double f2, void* params); -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); -double ddsIPWindowDuo(double f2, void* params); -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); - -//--time-frequency reassignment---------------------------------------------- -void TFReas(double& f, double& t, double& fslope, int Wid, cdouble* data, double* win, double* dwin, double* ddwin, double* plogaslope=0); -void TFReas(double& f, double t, double& a, double& ph, double& fslope, int Wid, cdouble* data, double* w, double* dw, double* ddw, double* win=0); - -//--additive and multiplicative reestimation routines------------------------ -typedef double (*TBasicAnalyzer)(double* fs, double* as, double* phs, double* das, cdouble* x, int Count, int Wid, int Offst, __int16* ref, int reserved, bool LogA); -void AdditiveUpdate(double* fs, double* as, double* phs, double* das, cdouble* x, int Count, int Wid, int Offst, TBasicAnalyzer BasicAnalyzer, int reserved, bool LogA=false); -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=false); -void MultiplicativeUpdate(double* fs, double* as, double* phs, double* das, cdouble* x, int Count, int Wid, int Offst, TBasicAnalyzer BasicAnalyzer, int reserved, bool LogA=false); -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=false); -void MultiplicativeUpdateF(double* fs, double* as, double* phs, __int16* x, int Fr, int frst, int fren, int Wid, int Offst); - -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=0); -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); -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=0); -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=0); - -//--local derivative algorithms - DAFx09------------------------------------- -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); -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=false); -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=false); - -//--the Abe-Smith estimator-------------------------------------------------- -void TFAS05(double& f, double& t, double& a, double& ph, double& aesp, double& fslope, int Wid, double* data, double* w, double res=1); -void TFAS05_enh(double& f, double& t, double& a, double& ph, double& aesp, double& fslope, int Wid, double* data, double* w, double res=1); -void TFAS05_enh(double& f, double& t, double& a, double& ph, int Wid, double* data, double* w, double res=1); - -//--piecewise derivative algorithms and tools-------------------------------- -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=0, cdouble* ds=0); -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=0, cdouble* ds=0); -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=0, cdouble* ds=0, double** dh=0); -void seth(int M, int T, double**& h, MList* mlist); -void setdh(int M, int T, double**& dh, MList* mlist); -void setdih(int M, int T, double**& dih, MList* mlist); -void setu(int I, int Wid, cdouble**& u, cdouble**& du, int WinOrder=2, MList* mlist=0); -void ssALinearSpline(int L, int T, int M, int& N, double*** &A, MList* mlist, int mode=0); -void ssACubicHermite(int L, int T, int M, int& N, double*** &A, MList* mlist, int mode=0); -void ssACubicSpline(int L, int T, int M, int& N, double*** &A, MList* mlist, int mode=0); -void ssLinearSpline(int L, int T, int M, int &N, double** &h, double*** &A, MList* mlist, int mode=0); -void ssCubicHermite(int L, int T, int M, int& N, double** &h, double*** &A, MList* mlist, int mode=0); -void ssCubicSpline(int L, int T, int M, int& N, double** &h, double*** &A, MList* mlist, int mode=0); -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=0, int WinOrder=2, int I=2, int endmode=0, cdouble* ds=0); -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=2, int I=2, int endmode=0, cdouble* ds=0); -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=2, int I=2, int endmode=0, cdouble* ds=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); - -//--local derivative algorithms - general------------------------------------ -/* - template DerivativeLSv: local derivative algorithm for estimating time-varying sinusoids, "v" version, - i.e. using tuned test functions. - - In: s[Wid]: waveform data - v[I][Wid], dv[I][Wid]: test functions and their derivatives - h[M+1][Wid]: basis functions - p0[p0s], q0[q0s]: zero-constraints, i.e. Re(lmd[p0[*]]) and Im(lmd[q0[*]]) are constrained zero. - Out: lmd[1:M]: coefficients of h[1:M]. - - Returns inner product of s and v[0]. -*/ -templatecdouble DerivativeLSv(int Wid, Ts* s, int I, cdouble** v, cdouble** dv, int M, double **h, cdouble* lmd, int p0s, int* p0, int q0s, int* q0) -{ - int Kr=M*2-p0s-q0s; //number of real unknowns apart from p0 and q0 - if (I=0){uind[up]=p; ind[p]=up; up++;} p++;} - if (up!=Kr) throw(""); - } - - cdouble* sv1=new cdouble[I]; - for (int i=0; i=0) - { - A[2*i][lind]=shv.x; - A[2*i+1][lind]=shv.y; - } - if ((lind=ind[2*m-1])>=0) - { - A[2*i][lind]=-shv.y; - A[2*i+1][lind]=shv.x; - } - } - - double* pq=new double[Kr]; - if (2*I==Kr) GECP(Kr, pq, A, (double*)sv1); - else LSLinear(2*I, Kr, pq, A, (double*)sv1); - - memset(lmd, 0, sizeof(double)*(M+1)*2); - for (int k=0; kcdouble DerivativeLS(int Wid, Ts* s, int I, double omg, Tu** u, Tu** du, int M, double **h, cdouble* lmd, int p0s, int* p0, int q0s, int* q0) -{ - cdouble** Allocate2(cdouble, I, Wid, v); - cdouble** Allocate2(cdouble, I, Wid, dv); - cdouble jomg=cdouble(0, omg); int hWid=Wid/2; - for (int c=0; ccdouble DerivativeLS_AmpPh(int Wid, int M, double** integr_h, cdouble* lmd, double omg, Tu* u0, cdouble sv0) -{ - cdouble e0=0; double hWid=Wid/2.0; - for (int n=0; n300) expo.x=300; - else if (expo.x<-300) expo.x=-300; - e0+=exp(expo)**(cdouble(u0[n]).rotate(omg*(n-hWid))); - } - return log(sv0/e0); -}//DerivativeLS_AmpPh - -/* - template DerivativeLS_AmpPh: amplitude and phase estimation in the local derivative algorithm, "u" - version. - - In: s[Wid]: waveform data - u0[Wid], omg: base-band test function and carrier frequency used for computing v0[] - integr_h[M+1][Wid]: integrals of basis functions - - Returns coefficient to integr_h[0]=1. -*/ -templatecdouble DerivativeLS_AmpPh(int Wid, int M, double** integr_h, cdouble* lmd, double omg, Tu* u0, Ts* s) -{ - cdouble ss0=0, e0=0; double hWid=Wid/2.0; - for (int n=0; n300) expo.x=300; - else if (expo.x<-300) expo.x=-300; - e0+=~exp(expo)*abs(u0[n]); - ss0+=s[n]**exp(expo)*abs(u0[n]); - } - return log(ss0/e0); -}//DerivativeLS_AmpPh - -cdouble DerivativeLSv_AmpPh(int, int, double**, cdouble*, cdouble*, cdouble); //the "v" version is implemented as a normal function in SinEst.cpp. - -/* - template DerivativeLSv: local derivative algorithm for estimating time-varying sinusoids, "v" version. - - In: s[Wid]: waveform data - v[I][Wid], dv[I][Wid]: test functions and their derivatives - h[M+1][Wid], integr_h[M+1][Wid]: basis functions and their integrals - p0[p0s], q0[q0s]: zero-constraints, i.e. Re(lmd[p0[*]]) and Im(lmd[q0[*]]) are constrained zero. - Out: lmd[M+1]: coefficients of h[M+1], including lmd[0]. - - No return value. -*/ -template void DerivativeLSv(int Wid, Ts* s, int I, cdouble** v, cdouble** dv, int M, double **h, double **integr_h, cdouble* lmd, int p0s, int* p0, int q0s, int* q0) -{ - cdouble sv0=DerivativeLSv(Wid, s, I, v, dv, M, h, lmd, p0s, p0, q0s, q0); - lmd[0]=DerivativeLSv_AmpPh(Wid, M, integr_h, lmd, v[0], sv0); -}//DerivativeLSv_AmpPh - -/*template DerivativeLSv: local derivative algorithm for estimating time-varying sinusoids, "u" version. - - In: s[Wid]: waveform data - u[I][Wid], du[I][Wid]: base-band test functions and their derivatives - omg: angular frequency onto which u[I] and du[I] are modulated to give the test functions - h[M+1][Wid], integr_h[M+1][Wid]: basis functions and their integrals - p0[p0s], q0[q0s]: zero-constraints, i.e. Re(lmd[p0[*]]) and Im(lmd[q0[*]]) are constrained zero. - Out: lmd[M+1]: coefficients of h[M+1], including lmd[0]. - - No return value. -*/ -templatevoid DerivativeLS(int Wid, Ts* s, int I, double omg, Tu** u, Tu** du, int M, double **h, double **integr_h, cdouble* lmd, int p0s, int* p0, int q0s, int* q0) -{ - cdouble sv0=DerivativeLS(Wid, s, I, omg, u, du, M, h, lmd, p0s, p0, q0s, q0); - lmd[0]=DerivativeLS_AmpPh(Wid, M, integr_h, lmd, omg, u[0], s); //sv0); -}//DerivativeLSv - -/* - template CosineWindows: generates the Hann^(K/2) window and its L-1 derivatives as Result[L][Wid+1] - - In: K, L, Wid - Out: w[L][Wid+1]: Hann^(K/2) window function and its derivatives up to order L-1 - - Returns pointer to w. w is created anew if w=0 is specified on start. -*/ -templateT** CosineWindows(int K, int Wid, T **w, int L=0) -{ - if (L<=0) L=K; - if (!w) {Allocate2(T, L, Wid+1, w);} - memset(w[0], 0, sizeof(T)*L*(Wid+1)); - int hWid=Wid/2, dWid=Wid*2; - double *s=new double[dWid+hWid], *c=&s[hWid]; //s[n]=sin(pi*n/N), n=0, ..., 2N-1 - double *C=new double[K+2], *lK=&C[K/2+1], piC=M_PI/Wid; - //C[i]=C(K, i)(-1)^i*2^(-K+1), the combination number, i=0, ..., K/2 - //ik[i]=(K-2i)^k*(M_PI/Wid)^k, i=0, ..., K/2 - //calculate C(K,i)(-1)^i*2^(-K+1) - C[0]=1.0/(1<<(K-1)); double lC=C[0]; for (int i=1; i+i<=K; i++){lC=lC*(K-i+1)/i; C[i]=(i%2)?(-lC):lC;} - //calculate sin/cos functions - for (int n=0; n300) e=300; - if (e<-300) e=-300; - s[t]=exp(cdouble(e, ph+(t*t*(_q+t*_p)))); - ph+=dph; - } -}//SinusoidExpA - -/* -//This is not used any longer as the recursion does not seem to help saving computation with all its overheads. -void SinusoidExp(cdouble* data, int CountSt, int CountEn, double a3, double a2, double a1, double a0, - double omg3, double omg2, double omg1, double omg0, double &ea, double &ph, bool add) -{ - int i; - double dea, ddea, dddea, ddddea, - dph, ddph, dddph, ddddph, - sph, cph, sdph, cdph, sddph, cddph, sdddph, cdddph, sddddph, cddddph, - e0=ea, e1=a0, e2=0.5*a1, e3=a2/3, e4=a3/4, - p0=ph, p1=omg0, p2=0.5*omg1, p3=omg2/3, p4=omg3/4, tmp; - if (CountSt==0) - { - dea=e1+e2+e3+e4; ddea=2*e2+6*e3+14*e4; dddea=6*e3+36*e4; ddddea=24*e3; - dph=p1+p2+p3+p4; ddph=2*p2+6*p3+14*p4; dddph=6*p3+36*p4; ddddph=24*p4; - } - else - { - ea=e0+CountSt*(e1+CountSt*(e2+CountSt*(e3+CountSt*e4))); - dea=e1+e2+e3+e4+CountSt*(2*e2+3*e3+4*e4+CountSt*(3*e3+6*e4+CountSt*4*e4)); - ddea=2*e2+6*e3+14*e4+CountSt*(6*e3+24*e4+CountSt*12*e4); - dddea=6*e3+36*e4+CountSt*24*e4; ddddea=24*e4; - ph=p0+CountSt*(p1+CountSt*(p2+CountSt*(p3+CountSt*p4))); - dph=p1+p2+p3+p4+CountSt*(2*p2+3*p3+4*p4+CountSt*(3*p3+6*p4+CountSt*4*p4)); - ddph=2*p2+6*p3+14*p4+CountSt*(6*p3+24*p4+CountSt*12*p4); - dddph=6*p3+36*p4+CountSt*24*p4; ddddph=24*p4; - } - sph=sin(ph), cph=cos(ph); - sdph=sin(dph), cdph=cos(dph); - sddph=sin(ddph), cddph=cos(ddph); - sdddph=sin(dddph), cdddph=cos(dddph); - sddddph=sin(ddddph), cddddph=cos(ddddph); - if (add) - { - for (i=CountSt; i=xs[Fr-1] - add: specifies if the resynthesized sinusoid is to be added to or to replace the content of output buffer - Out: xrec[0:den-dst-1]: output buffer hosting synthesized sinusoid from dst to den. - phs[Fr]: phase angles at xs[Fr] - - Returns pointer to xrec. -*/ -double* SynthesizeSinusoid(double* xrec, int dst, int den, double* phs, int Fr, double* xs, double* fs, double* as, bool add, bool* terminatetag) -{ - double *f3=new double[Fr*8], *f2=&f3[Fr], *f1=&f3[Fr*2], *f0=&f3[Fr*3], - *a3=&f3[Fr*4], *a2=&a3[Fr], *a1=&a3[Fr*2], *a0=&a3[Fr*3]; - CubicSpline(Fr-1, f3, f2, f1, f0, xs, fs, 1, 1); - CubicSpline(Fr-1, a3, a2, a1, a0, xs, as, 1, 1); - double ph=phs[0]; - for (int fr=0; fr=xs[Fr-1] - add: specifies if the resynthesized sinusoid is to be added to or to replace the content of output - buffer - Out: xrecm[0:den-dst-1]: output buffer hosting synthesized sinusoid from dst to den. - - Returns pointer to xrecm. -*/ -double* SynthesizeSinusoidP(double* xrecm, int dst, int den, double* phs, int Fr, double* xs, double* fs, double* as, bool add) -{ - double *f3=new double[Fr*8], *f2=&f3[Fr], *f1=&f3[Fr*2], *f0=&f3[Fr*3], - *a3=&f3[Fr*4], *a2=&a3[Fr], *a1=&a3[Fr*2], *a0=&a3[Fr*3]; - CubicSpline(Fr-1, f3, f2, f1, f0, xs, fs, 1, 1); - CubicSpline(Fr-1, a3, a2, a1, a0, xs, as, 1, 1); - for (int fr=0; fr -#include -#include "WindowFunctions.h" -#include "align8.h" -//--------------------------------------------------------------------------- - -/* - function I0: Bessel function of order zero - - Returns the Bessel function of x. -*/ -double I0(double x) -{ - const double eps=1e-9; - - int n=1; - double S=1, D=1, T; - - while (D>eps*S) - { - T=x/(2*n++); - D*=T*T; - S+=D; - } - return S; -}//I0 - -/* - function FillWindow: fills a buffer $Result with a window function. - - In: wt:window type - Count: window size - ips & ups: extra window specificatin parameters - Out: newwindow[Count+1]: the window function. - - No return value. This function is designed assuming Count being even, and Count/2 is the symmetry - centre of newwindow. newwindow has physical size Count+1 for compatibility purpose. For all vanishing - windows (e.g. Hann) newwindow[0]=newwindow[Count]=0. -*/ -void FillWindow(double* Result, WindowType wt, int Count, int* ips, double* dps) -{ - switch(wt) - { - case wtRectangle: - for (int i=0; i<=Count; i++) - Result[i]=1; - break; - case wtTriangular: - for (int i=0; i<=Count; i++) - Result[i]=1-2*fabs(i-Count/2.0)/Count; - break; - case wtHamming: - for (int i=0; i<=Count; i++) - Result[i]=(0.54-0.46*cos(2*M_PI*i/Count)); - break; - case wtBlackman: - for (int i=0; i<=Count; i++) - Result[i]=0.42-0.5*cos(2*M_PI*i/Count)+0.08*cos(4*M_PI*i/Count); - break; - case wtGaussian: - { - double num=*dps*M_PI*M_PI/2/Count/Count; - for (int i=0; i<=Count; i++) - Result[i]=exp(-(i-Count/2.0)*(i-Count/2.0)*num); - break; - } - case wtKaiser: - { - double ldps=*dps*M_PI*M_PI/2/Count; - double den=I0(0.5*Count*ldps); - for (int i=0; i<=Count; i++) - Result[i]=I0(ldps*sqrt(0.25*Count*Count-(i-Count*0.5)*(i-Count*0.5)))/den; - break; - } - case wtHalfCosine: - { - for (int i=0; i<=Count; i++) - Result[i]=sin(M_PI*i/Count); - break; - } - case wtHann: - { - for (int i=0; i<=Count; i++) - Result[i]=(0.5-cos(M_PI*2*i/Count)/2); - break; - } - case wtHannSqr: - { - for (int i=0; i<=Count; i++) - Result[i]=(3-4*cos(M_PI*2*i/Count)+cos(M_PI*4*i/Count))/8; - break; - } - case wtHann3sqrt: - { - for (int i=0; i<=Count; i++) - { - double tmp=sin(M_PI*i/Count); - Result[i]=tmp*tmp*tmp; - } - break; - } - } -}//FillWindow - -/* - function NewWindow: creates a window function. - - In: wt: window type - Count: window size - ips & ups: extra window specificatin parameters - Out: newwindow[Count+1]: the window function. - - Returns pointer to newwindow. newwindow is created anew if newwindow=0 is specified on start. -*/ -double* NewWindow(WindowType wt, int Count, int* ips, double* dps, double* newwindow) -{ - double* Result=newwindow; if (!Result) Result=new double[Count+1]; - FillWindow(Result, wt, Count, ips, dps); - return Result; -}//NewWindow - -/* - function NewWindow8: 8-byte aligned version of NewWindow. - - In: wt: window type - Count: window size - ips & ups: extra window specificatin parameters - Out: newwindow[Count+1]: the window function. - - Returns pointer to newwindow. newwindow is created anew and 8-byte aligned if newwindow=0 is - specified on start. However, if newwindow is not 8-byte aligned on start, the unaligned buffer is - returned. -*/ -double* NewWindow8(WindowType wt, int Count, int* ips, double* dps, double* newwindow) -{ - double* Result=newwindow; if (!Result) Result=(double*)malloc8(sizeof(double)*(Count+1)); - FillWindow(Result, wt, Count, ips, dps); - return Result; -}//NewWindow8 - -/* - function NewdWindow: computes the derivative of a window function. - - In: wt: window type - Count: window size - ips & ups: extra window specificatin parameters - Out: newdwindow[Count+1]: the derivative window function. - - Returns pointer to newdwindow. newdwindow is created anew if newdwindow=0 is specified on start. -*/ -double* NewdWindow(WindowType wt, int Count, int* ips, double* dps, double* newdwindow) -{ - double* Result=newdwindow; if (!Result) Result=new double[Count+1]; - double piiCount=M_PI/Count; - switch(wt) - { - case wtRectangle: - memset(Result, 0, sizeof(double)*(Count+1)); - break; - case wtTriangular: - throw("Trying to differentiate triangular window."); - break; - case wtHamming: - for (int i=0; i<=Count; i++) - Result[i]=0.92*piiCount*sin(2*piiCount*i); - break; - case wtBlackman: - for (int i=0; i<=Count; i++) - Result[i]=piiCount*sin(2*piiCount*i)-0.32*piiCount*sin(4*piiCount*i); - break; - case wtGaussian: - throw("Trying to differentiate Gaussian window."); - break; - case wtKaiser: - throw("Trying to differentiate Kaiser window."); - break; - case wtHalfCosine: - { - for (int i=0; i<=Count; i++) - Result[i]=piiCount*cos(piiCount*i); - break; - } - case wtHann: - { - for (int i=0; i<=Count; i++) - Result[i]=piiCount*sin(2*piiCount*i); - break; - } - case wtHannSqr: - { - for (int i=0; i<=Count; i++) - Result[i]=piiCount*sin(2*piiCount*i)-0.5*piiCount*sin(4*piiCount*i); - break; - } - case wtHann3sqrt: - { - for (int i=0; i<=Count; i++) - { - double s=sin(M_PI*i/Count), c=cos(M_PI*i/Count); - Result[i]=3*piiCount*s*s*c; - } - } - } - return Result; -}//NewdWindow - -/* - function NewddWindow: computes the 2nd-order derivative of a window function. - - In: wt: window type - Count: window size - ips & ups: extra window specificatin parameters - Out: newddwindow[Count+1]: the 2nd-order derivative window function. - - Returns pointer to newddwindow. newddwindow is created anew if newddwindow=0 is specified on start. -*/ -double* NewddWindow(WindowType wt, int Count, int* ips, double* dps, double* newddwindow) -{ - double* Result=newddwindow; if (!Result) Result=new double[Count+1]; - double piiCount=M_PI/Count; - double piC2=piiCount*piiCount; - switch(wt) - { - case wtRectangle: - memset(Result, 0, sizeof(double)*(Count+1)); - break; - case wtTriangular: - throw("Trying to double-differentiate triangular window."); - break; - case wtHamming: - for (int i=0; i<=Count; i++) - Result[i]=1.84*piC2*cos(2*piiCount*i); - break; - case wtBlackman: - for (int i=0; i<=Count; i++) - Result[i]=2*piC2*cos(2*piiCount*i)-1.28*piC2*cos(4*piiCount*i); - break; - case wtGaussian: - throw("Trying to double-differentiate Gaussian window."); - break; - case wtKaiser: - throw("Trying to double-differentiate Kaiser window."); - break; - case wtHalfCosine: - { - for (int i=0; i<=Count; i++) - Result[i]=-piC2*sin(piiCount*i); - break; - } - case wtHann: - { - for (int i=0; i<=Count; i++) - Result[i]=2*piC2*cos(2*piiCount*i); - break; - } - case wtHannSqr: - { - for (int i=0; i<=Count; i++) - Result[i]=2*piC2*cos(2*piiCount*i)-2*piC2*cos(4*piiCount*i); - break; - } - case wtHann3sqrt: - { - for (int i=0; i<=Count; i++) - { - double s=sin(M_PI*i/Count), c=cos(M_PI*i/Count); - Result[i]=3*piC2*(2*c*c-s*s)*s; - } - break; - } - } - return Result; -}//NewddWindow - -/* - function NewdddWindow: computes the 3rd-order derivative of a window function. - In: wt: window type - Count: window size - ips & ups: extra window specificatin parameters - Out: newdddwindow[Count+1]: the 3rd-order derivative window function. - - Returns pointer to newdddwindow. newdddwindow is created anew if newdddwindow=0 is specified on start. -*/ -double* NewdddWindow(WindowType wt, int Count, int* ips, double* dps, double* newdddwindow) -{ - double* Result=newdddwindow; if (!Result) Result=new double[Count+1]; - double piiCount=M_PI/Count; - double piC2=piiCount*piiCount; - double piC3=piiCount*piC2; - switch(wt) - { - case wtRectangle: - memset(Result, 0, sizeof(double)*(Count+1)); - break; - case wtTriangular: - throw("Trying to triple-differentiate triangular window."); - break; - case wtHamming: - for (int i=0; i<=Count; i++) - Result[i]=-3.68*piC3*sin(2*piiCount*i); - break; - case wtBlackman: - for (int i=0; i<=Count; i++) - Result[i]=-4*piC3*sin(2*piiCount*i)+5.12*piC3*sin(4*piiCount*i); - break; - case wtGaussian: - throw("Trying to triple-differentiate Gaussian window."); - break; - case wtKaiser: - throw("Trying to triple-differentiate Kaiser window."); - break; - case wtHalfCosine: - { - for (int i=0; i<=Count; i++) - Result[i]=-piC3*cos(piiCount*i); - break; - } - case wtHann: - { - for (int i=0; i<=Count; i++) - Result[i]=-4*piC3*sin(2*piiCount*i); - break; - } - case wtHannSqr: - { - for (int i=0; i<=Count; i++) - Result[i]=-4*piC3*sin(2*piiCount*i)+8*piC3*sin(4*piiCount*i); - break; - } - case wtHann3sqrt: - throw("Trying to triple-differentiate Hann^1.5 window."); - break; - } - return Result; -}//NewdddWindow - -//--------------------------------------------------------------------------- -/* - function windowspec: computes a few descriptors of a cosine family window. A window function in the - cosine window family is the linear combination of a few cosine functions, therefore has a cosine - decomposition. - - In: wt: window type - N: window size - Out: c[M+1], coefficients of cosine decomposition - iH2: reciprocal of square of L2 norm, - d[2M+1]: self-convolution of c[], optional - - No return value. -*/ -void windowspec(WindowType wt, int N, int* M, double* c, double* iH2, double* d) -{ - switch(wt) - { - case wtRectangle: - M[0]=0, c[0]=1, iH2[0]=1.0/N/N; - if (d) d[0]=1; - break; - case wtHamming: - M[0]=1, c[0]=0.54, c[1]=0.23, iH2[0]=1.0/(0.3974*N*N); - if (d) d[0]=0.3974, d[1]=0.2484, d[2]=0.0529; - break; - case wtBlackman: - M[0]=2, c[0]=0.42, c[1]=0.25, c[2]=0.04, iH2[0]=1.0/(0.3046*N*N); - if (d) d[0]=0.3046, d[1]=0.23, d[2]=0.0961, d[4]=0.02, d[5]=0.0016; - break; - case wtHann: - M[0]=1, c[0]=0.5, c[1]=0.25, iH2[0]=1.0/(0.375*N*N); - if (d) d[0]=0.375, d[1]=0.25, d[2]=0.0625; - break; - default: - M[0]=1, c[0]=0.5, c[1]=0.25, iH2[0]=1.0/(0.375*N*N); - if (d) d[0]=0.375, d[1]=0.25, d[2]=0.0625; - break; - } -}//windowspec diff -r 6422640a802f -r fc19d45615d1 WindowFunctions.h --- a/WindowFunctions.h Tue Oct 05 10:45:57 2010 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,33 +0,0 @@ -#ifndef WindowFunctionsH -#define WindowFunctionsH - -/* - WindowFunctions.cpp - implements a few common window functions. -*/ - -enum WindowType -{ - wtRectangle, - wtTriangular, - wtHamming, - wtBlackman, - wtGaussian, - wtKaiser, - wtHalfCosine, - wtHann, - wtHannSqr, - wtHann3sqrt -}; - -//--window function computation routines------------------------------------- -void FillWindow(double* newwindow, WindowType wt, int Count, int* ips=0, double* dps=0); -double* NewWindow(WindowType wt, int Count, int* ips=0, double* dps=0, double* newwindow=0); -double* NewWindow8(WindowType wt, int Count, int* ips=0, double* dps=0, double* newwindow=0); -double* NewdWindow(WindowType wt, int Count, int* ips=0, double* dps=0, double* newdwindow=0); -double* NewddWindow(WindowType wt, int Count, int* ips=0, double* dps=0, double* newddwindow=0); -double* NewdddWindow(WindowType wt, int Count, int* ips=0, double* dps=0, double* newdddwindow=0); - -//--other functions---------------------------------------------------------- -void windowspec(WindowType wt, int N, int* M, double* c, double* iH2, double* d=0); - -#endif diff -r 6422640a802f -r fc19d45615d1 fft.cpp --- a/fft.cpp Tue Oct 05 10:45:57 2010 +0100 +++ b/fft.cpp Tue Oct 05 11:04:40 2010 +0100 @@ -1,6 +1,6 @@ //--------------------------------------------------------------------------- -#include +#include #include #include "fft.h" diff -r 6422640a802f -r fc19d45615d1 hs.cpp --- a/hs.cpp Tue Oct 05 10:45:57 2010 +0100 +++ b/hs.cpp Tue Oct 05 11:04:40 2010 +0100 @@ -4,8 +4,8 @@ #include "align8.h" #include "arrayalloc.h" #include "procedures.h" -#include "SinEst.h" -#include "SinSyn.h" +#include "sinest.h" +#include "sinsyn.h" #include "splines.h" #include "xcomplex.h" #ifdef I diff -r 6422640a802f -r fc19d45615d1 hs.h --- a/hs.h Tue Oct 05 10:45:57 2010 +0100 +++ b/hs.h Tue Oct 05 11:04:40 2010 +0100 @@ -8,12 +8,12 @@ */ //--------------------------------------------------------------------------- -#include +#include #include "arrayalloc.h" #include "align8.h" #include "fft.h" -#include "QuickSpec.h" -#include "TStream.h" +#include "quickspec.h" +#include "tstream.h" #define ATOM_LOCALANCHOR 1 #define HS_CONSTF 1 diff -r 6422640a802f -r fc19d45615d1 hssf.cpp --- a/hssf.cpp Tue Oct 05 10:45:57 2010 +0100 +++ b/hssf.cpp Tue Oct 05 11:04:40 2010 +0100 @@ -2,10 +2,10 @@ #include -#include +#include #include "hssf.h" #include "arrayalloc.h" -#include "Matrix.h" +#include "matrix.h" #include "vibrato.h" //--------------------------------------------------------------------------- diff -r 6422640a802f -r fc19d45615d1 matrix.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/matrix.cpp Tue Oct 05 11:04:40 2010 +0100 @@ -0,0 +1,2245 @@ +//--------------------------------------------------------------------------- +#include +#include +#include "matrix.h" +//--------------------------------------------------------------------------- +/* + function BalanceSim: applies a similarity transformation to matrix a so that a is "balanced". This is + used by various eigenvalue evaluation routines. + + In: matrix A[n][n] + Out: balanced matrix a + + No return value. +*/ +void BalanceSim(int n, double** A) +{ + if (n<2) return; + const int radix=2; + double sqrdx; + sqrdx=radix*radix; + bool finish=false; + while (!finish) + { + finish=true; + for (int i=0; iar) + { + ac/=radix; + sc/=sqrdx; + } + } + if ((sc+sr)/ac<0.95*s) + { + finish=false; + ar=1.0/ac; + for (int j=0; jAdd(Z, 2);} + int sizeN=sizeof(double)*N; + for (int m=0; mAdd(Z, 2);} + int sizeN=sizeof(cdouble)*N; + for (int m=0; mAdd(z, 1);} + memcpy(z, a, sizeof(double)*N); + return z; +}//Copy +cdouble* Copy(int N, cdouble* z, cdouble* a, MList* List) +{ + if (!z){z=new cdouble[N]; if (List) List->Add(z, 1);} + memcpy(z, a, sizeof(cdouble)*N); + return z; +}//Copy +//version without specifying pre-allocated z +double* Copy(int N, double* a, MList* List){return Copy(N, 0, a, List);} +cdouble* Copy(int N, cdouble* a, MList* List){return Copy(N, 0, a, List);} + +//--------------------------------------------------------------------------- +/* + function det: computes determinant by Gaussian elimination method with column pivoting + + In: matrix A[N][N] + + Returns det(A). On return content of matrix A is unchanged if mode=0. +*/ +double det(int N, double** A, int mode) +{ + int c, p, ip, *rp=new int[N]; for (int i=0; ifabs(A[rp[p]][i])) p=ip; ip++;} + if (A[rp[p]][i]==0) {result=0; goto ret;} + if (p!=i) {c=rp[i]; rp[i]=rp[p]; rp[p]=c; result=-result;} + for (int j=i+1; jmp) mp=mm, p=ip; ip++;} + if (mp==0) {result=0; goto ret;} + if (p!=i) {c=rp[i]; rp[i]=rp[p]; rp[p]=c;} + for (int j=i+1; j2) {l=m0-(m1-m0)*(m1-m0)/(m-2*m1+m0); delete[] y; return 0;} + k++; m0=m1; m1=m; + } + delete[] y; return 1; +}//EigPowerA + +//--------------------------------------------------------------------------- +/* + function EigPowerI: Inverse power method for solving the eigenvalue given an approximate non-zero + eigenvector. + + In: matrix A[N][N], approximate eigenvector x[N]. + Out: eigenvalue l, eigenvector x[N]. + + Returns 0 is successful. Content of matrix A is unchangd on return. Initial x[N] must not be zero. +*/ +int EigPowerI(int N, double& l, double* x, double** A, double ep, int maxiter) +{ + int sizeN=sizeof(double)*N; + double* y=new double[N]; MultiplyXy(N, N, y, A, x); + double q=Inner(N, x, y)/Inner(N, x, x), dt; + double** aa=new double*[N]; aa[0]=new double[N*N]; + for (int i=0; i=N) {delete[] rp; return 1;} + if (p!=i){c=rp[i]; rp[i]=rp[p]; rp[p]=c;} + for (int j=i+1; j=0; i--) + { + x[i]=b[rp[i]]; for (int j=i+1; jfabs(A[rp[p]][i])/s[rp[p]]) p=ip; ip++;} + if (A[rp[p]][i]==0) {delete[] s; delete[] rp; return 1;} + if (p!=i) {c=rp[i]; rp[i]=rp[p]; rp[p]=c;} + for (int j=i+1; j=0; i--) + { + x[i]=b[rp[i]]; for (int j=i+1; j=0; n--) + { + double xn=a[n]; + for (int m=n+1; m=0; n--) + { + for (int m=n+1; mA. + + In: matrix A[N][N] + Out: matrix A[N][N] + + Returns the determinant of the inverse matrix, 0 on failure. +*/ +double GICP(int N, double** A) +{ + int c, p, ip, *rp=new int[N]; for (int i=0; ifabs(A[rp[p]][i])) p=ip; ip++;} + if (A[rp[p]][i]==0) {delete[] rp; return 0;} + if (p!=i) {c=rp[i]; rp[i]=rp[p]; rp[p]=c; result=-result;} + result/=A[rp[i]][i]; + for (int j=i+1; j~A[rp[p]][i]) p=ip; ip++;} + if (A[rp[p]][i]==0) {delete[] rp; return 0;} + if (p!=i) {c=rp[i]; rp[i]=rp[p]; rp[p]=c; result=-result;} + result=result/(A[rp[i]][i]); + for (int j=i+1; jX. + + In: matrix A[N][N] + Out: matrix X[N][N] + + Returns the determinant of the inverse matrix, 0 on failure. +*/ +double GICP(int N, double** X, double** A) +{ + Copy(N, X, A); + return GICP(N, X); +}//GICP + +//--------------------------------------------------------------------------- +/* + function GILT: inv(lower trangular of A)->lower trangular of A + + In: matrix A[N][N] + Out: matrix A[N][N] + + Returns the determinant of the lower trangular of A +*/ +double GILT(int N, double** A) +{ + double result=1; + A[0][0]=1/A[0][0]; + for (int i=1; iupper trangular of A + + In: matrix A[N][N] + Out: matrix A[N][N] + + Returns the determinant of the upper trangular of A +*/ +double GIUT(int N, double** A) +{ + double result=1; + A[0][0]=1/A[0][0]; + for (int i=1; iA. + + In: matrix A[N][N] + Out: matrix A[N][N] + + Returns the determinant of the inverse matrix, 0 on failure. +*/ +double GISCP(int N, double** A) +{ + int c, p, ip, *rp=new int[N]; for (int i=0; ifabs(A[rp[p]][i]/s[rp[p]])) p=ip; ip++;} + if (A[rp[p]][i]==0) {delete[] s; delete[] rp; return 0;} + if (p!=i) {c=rp[i]; rp[i]=rp[p]; rp[p]=c; result=-result;} + result/=A[rp[i]][i]; + for (int j=i+1; jX. + + In: matrix A[N][N] + Out: matrix X[N][N] + + Returns the determinant of the inverse matrix, 0 on failure. +*/ +double GISCP(int N, double** X, double** A) +{ + Copy(N, X, A); + return GISCP(N, X); +}//GISCP + +//--------------------------------------------------------------------------- +/* + function GSI: Gaussian-Seidel iterative algorithm for solving linear system Ax=b. Breaks down if any + Aii=0, like the Jocobi method JI(...). + + Gaussian-Seidel iteration is x(k)=(D-L)^(-1)(Ux(k-1)+b), where D is diagonal, L is lower triangular, + U is upper triangular and A=L+D+U. + + In: matrix A[N][N], vector b[N], initial vector x0[N] + Out: vector x0[N] + + Returns 0 is successful. Contents of matrix A and vector b remain unchanged on return. +*/ +int GSI(int N, double* x0, double** A, double* b, double ep, int maxiter) +{ + double e, *x=new double[N]; + int k=0, sizeN=sizeof(double)*N; + while (k=maxiter) return 1; + return 0; +}//GSI + +//--------------------------------------------------------------------------- +/* + function Hessenb: reducing a square matrix A to upper Hessenberg form + + In: matrix A[N][N] + Out: matrix A[N][N], in upper Hessenberg form + + No return value. +*/ +void Hessenb(int N, double** A) +{ + double x, y; + for (int m=1; m fabs(x)) + { + x=A[j][m-1]; + i=j; + } + } + if (i!=m) + { + for (int j=m-1; j=1; i--) + { + int l=i-1; + double h=0, scale=0; + if (l>0) + { + for (int k=0; k<=l; k++) scale+=fabs(A[i][k]); + if (scale==0.0) sd[i]=A[i][l]; + else + { + for (int k=0; k<=l; k++) + { + A[i][k]/=scale; + h+=A[i][k]*A[i][k]; + } + double f=A[i][l]; + double g=(f>=0?-sqrt(h): sqrt(h)); + sd[i]=scale*g; + h-=f*g; + A[i][l]=f-g; + f=0; + for (int j=0; j<=l; j++) + { + A[j][i]=A[i][j]/h; + g=0; + for (int k=0; k<=j; k++) g+=A[j][k]*A[i][k]; + for (int k=j+1; k<=l; k++) g+=A[k][j]*A[i][k]; + sd[j]=g/h; + f+=sd[j]*A[i][j]; + } + double hh=f/(h+h); + for (int j=0; j<=l; j++) + { + f=A[i][j]; + sd[j]=g=sd[j]-hh*f; + for (int k=0; k<=j; k++) A[j][k]-=(f*sd[k]+g*A[i][k]); + } + } + } + else + sd[i]=A[i][l]; + d[i]=h; + } + + d[0]=sd[0]=0; + + for (int i=0; i=maxiter) return 1; + else return 0; +}//JI + +//--------------------------------------------------------------------------- +/* + function LDL: LDL' decomposition A=LDL', where L is lower triangular and D is diagonal identical l and + a allowed. + + The symmetric matrix A is positive definite iff A can be factorized as LDL', where L is lower + triangular with ones on its diagonal and D is diagonal with positive diagonal entries. + + If a symmetric matrix A can be reduced by Gaussian elimination without row interchanges, then it can + be factored into LDL', where L is lower triangular with ones on its diagonal and D is diagonal with + non-zero diagonal entries. + + In: matrix A[N][N] + Out: lower triangular matrix L[N][N], vector d[N] containing diagonal elements of D + + Returns 0 if successful. Content of matrix A is unchanged on return. +*/ +int LDL(int N, double** L, double* d, double** A) +{ + double* v=new double[N]; + + if (A[0][0]==0) {delete[] v; return 1;} + d[0]=A[0][0]; for (int j=1; j=N. Use of this function requires + the submatrix A[N][N] be invertible. + + In: matrix A[M][N], vector y[M], M>=N. + Out: vector x[N]. + + No return value. Contents of matrix A and vector y are unchanged on return. +*/ +void LSLinear2(int M, int N, double* x, double** A, double* y) +{ + double** A1=Copy(N, N, 0, A); + LU(N, x, A1, y); + if (M>N) + { + double** B=&A[N]; + double* Del=MultiplyXy(M-N, N, B, x); + MultiAdd(M-N, Del, Del, &y[N], -1); + double** A2=MultiplyXtX(N, N, A); + MultiplyXtX(N, M-N, A1, B); + MultiAdd(N, N, A2, A2, A1, 1); + double* b2=MultiplyXty(N, M-N, B, Del); + double* dx=new double[N]; + GESCP(N, dx, A2, b2); + MultiAdd(N, x, x, dx, -1); + delete[] dx; + delete[] Del; + delete[] b2; + DeAlloc2(A2); + } + DeAlloc2(A1); +}//LSLinear2 + +//--------------------------------------------------------------------------- +/* + function LU: LU decomposition A=LU, where L is lower triangular with diagonal entries 1 and U is upper + triangular. + + LU is possible if A can be reduced by Gaussian elimination without row interchanges. + + In: matrix A[N][N] + Out: matrices L[N][N] and U[N][N], subject to input values of L and U: + if L euqals NULL, L is not returned + if U equals NULL or A, U is returned in A, s.t. A is modified + if L equals A, L is returned in A, s.t. A is modified + if L equals U, L and U are returned in the same matrix + when L and U are returned in the same matrix, diagonal of L (all 1) is not returned + + Returns 0 if successful. +*/ +int LU(int N, double** L, double** U, double** A) +{ + double* diagl=new double[N]; + for (int i=0; i=0; i--) + { + x[i]/=A[i][i]; + for (int j=0; jb[i-j, j] + the main diagonal is b[0][0]~b[0][N-1] + the 1st upper subdiagonal is b[-1][1]~b[-1][N-1] + the 2nd upper subdiagonal is b[-2][2]~b[-2][N-1] + the 1st lower subdiagonal is b[1][0]~b[1][N-2] + the 2nd lower subdiagonal is b[2][0]~b[2][N-3] + + Out: L[N][N] and U[N][N], main diagonal of L being all 1 (probably), stored in a compact format in + b[-2:2][N]. + + Returns 0 if successful. +*/ +int LU_PD(int N, double** b) +{ + if (b[0][0]==0) return 1; + b[1][0]/=b[0][0], b[2][0]/=b[0][0]; + + //i=1, not to double b[*][i-2], b[-2][i] + b[0][1]-=b[1][0]*b[-1][1]; + if (b[0][1]==0) return 2; + b[-1][2]-=b[1][0]*b[-2][2]; + b[1][1]-=b[2][0]*b[-1][1]; + b[1][1]/=b[0][1]; + b[2][1]/=b[0][1]; + + for (int i=2; i=0; i--) + c[i]=(c[i]-b[-1][i+1]*c[i+1]-b[-2][i+2]*c[i+2])/b[0][i]; + } + return result; +}//LU_PD + +//--------------------------------------------------------------------------- +/* + function LUCP: LU decomposition A=LU with column pivoting + + In: matrix A[N][N] + Out: matrix A[N][N] now holding L and U by L_U[i][j]=A[ind[i]][j], where L_U + hosts L and U according to mode: + mode=0: L diag=abs(U diag), U diag as return + mode=1: L diag=1, U diag as return + mode=2: U diag=1, L diag as return + + Returns the determinant of A. +*/ +double LUCP(double **A, int N, int *ind, int &parity, int mode) +{ + double det=1; + parity=1; + + for (int i=0; ivmax) vmax=tmp; + if (vmax==0) { parity=0; goto deletenorm; } //det=0 at this point + norm[i]=1/vmax; + } + + int maxind; + for (int j=0; j=j + double tmp=A[i][j]; for (int k=0; k=vmax) maxind=i, vmax=tmp2; + } + if (vmax==0) { parity=0; goto deletenorm; } //pivot being zero + if (j!=maxind) + { + //do column pivoting: switching rows + for (int k=0; kAdd(z, 1);} \ + for (int m=0; mAdd(z, 1); \ + for (int m=0; m=maxiter) return 1; + double g=(d[l+1]-d[l])/(2*sd[l]); + double r=sqrt(g*g+1); + g=d[m]-d[l]+sd[l]/(g+(g>=0?r:-r)); + double s=1, c=1, p=0; + int i; + for (i=m-1; i>=l; i--) + { + double f=s*sd[i], b=c*sd[i]; + sd[i+1]=(r=sqrt(f*f+g*g)); + if (r==0) + { + d[i+1]-=p; + sd[m]=0; + break; + } + s=f/r, c=g/r; + g=d[i+1]-p; + r=(d[i]-g)*s+2.0*c*b; + p=s*r; + d[i+1]=g+p; + g=c*r-b; + for (int k=0; k=l) continue; + d[l]-=p; + sd[l]=g; + sd[m]=0.0; + } + } + while (m!=l); + } + return 0; +}//QL + +//--------------------------------------------------------------------------- +/* + function QR: nr version of QR method for solving upper Hessenberg system A. This is compatible with + Hessenb method. + + In: matrix A[N][N] + Out: vector ev[N] of eigenvalues + + Returns 0 on success. Content of matrix A is destroyed on return. +*/ +int QR(int N, double **A, cdouble* ev) +{ + int n=N, m, l, k, j, iter, i, mmin, maxiter=30; + double **a=A, z, y, x, w, v, u, t=0, s, r, q, p, a1=0; + for (i=0; i0?i-1:0; j=0) + { + iter=0; + do + { + for (l=n; l>0; l--) + { + s=fabs(a[l-1][l-1])+fabs(a[l][l]); + if (s==0) s=a1; + if (fabs(a[l][l-1])+s==s) {a[l][l-1]=0; break;} + } + x=a[n][n]; + if (l==n) {ev[n].x=x+t; ev[n--].y=0;} + else + { + y=a[n-1][n-1], w=a[n][n-1]*a[n-1][n]; + if (l==(n-1)) + { + p=0.5*(y-x); + q=p*p+w; + z=sqrt(fabs(q)); + x+=t; + if (q>=0) + { + z=p+(p>=0?z:-z); + ev[n-1].x=ev[n].x=x+z; + if (z) ev[n].x=x-w/z; + ev[n-1].y=ev[n].y=0; + } + else + { + ev[n-1].x=ev[n].x=x+p; + ev[n].y=z; ev[n-1].y=-z; + } + n-=2; + } + else + { + if (iter>=maxiter) return 1; + if (iter%10==9) + { + t+=x; + for (i=0; i<=n; i++) a[i][i]-=x; + s=fabs(a[n][n-1])+fabs(a[n-1][n-2]); + y=x=0.75*s; + w=-0.4375*s*s; + } + iter++; + for (m=n-2; m>=l; m--) + { + z=a[m][m]; + r=x-z; s=y-z; + p=(r*s-w)/a[m+1][m]+a[m][m+1]; q=a[m+1][m+1]-z-r-s; r=a[m+2][m+1]; + s=fabs(p)+fabs(q)+fabs(r); + p/=s; q/=s; r/=s; + if (m==l) break; + u=fabs(a[m][m-1])*(fabs(q)+fabs(r)); + v=fabs(p)*(fabs(a[m-1][m-1])+fabs(z)+fabs(a[m+1][m+1])); + if (u+v==v) break; + } + for (i=m+2; i<=n; i++) + { + a[i][i-2]=0; + if (i!=m+2) a[i][i-3]=0; + } + for (k=m; k<=n-1; k++) + { + if (k!=m) + { + p=a[k][k-1]; + q=a[k+1][k-1]; + r=0; + if (k!=n-1) r=a[k+2][k-1]; + x=fabs(p)+fabs(q)+fabs(r); + if (x!=0) p/=x, q/=x, r/=x; + } + if (p>=0) s=sqrt(p*p+q*q+r*r); + else s=-sqrt(p*p+q*q+r*r); + if (s!=0) + { + if (k==m) + { + if (l!=m) a[k][k-1]=-a[k][k-1]; + } + else a[k][k-1]=-s*x; + p+=s; + x=p/s; y=q/s; z=r/s; q/=p; r/=p; + for (j=k; j<=n; j++) + { + p=a[k][j]+q*a[k+1][j]; + if (k!=n-1) + { + p+=r*a[k+2][j]; + a[k+2][j]-=p*z; + } + a[k+1][j]-=p*y; a[k][j]-=p*x; + } + mmin=nl+1); + } + return 0; +}//QR + +/* + function QR_GS: QR decomposition A=QR using Gram-Schmidt method + + In: matrix A[M][N], M>=N + Out: Q[M][N], R[N][N] + + No return value. +*/ +void QR_GS(int M, int N, double** A, double** Q, double** R) +{ + double *u=new double[M]; + for (int n=0; n=N + Out: Q[M][M], R[M][N] + + No return value. +*/ +void QR_householder(int M, int N, double** A, double** Q, double** R) +{ + double *u=new double[M*3], *ur=&u[M], *qu=&u[M*2]; + for (int m=0; m0) alf=-alf; + for (int m=n; mAdd(z, 2);} + for (int m=0; m1) memset(A[1], 0, sizeof(double)*N*(N-1)); + for (int i=1; i=maxiter) return 1; + return 0; +}//SorI + +//--------------------------------------------------------------------------- +//Submatrix routines + +/* + function SetSubMatrix: copy matrix x[Y][X] into matrix z at (Y1, X1). + + In: matrix x[Y][X], matrix z with dimensions no less than [Y+Y1][X+X1] + Out: matrix z, updated. + + No return value. +*/ +void SetSubMatrix(double** z, double** x, int Y1, int Y, int X1, int X) +{ + for (int y=0; yAdd(z, 2);} + for (int y=0; yAdd(z, 1);} + memcpy(z, &x[X1], sizeof(cdouble)*X); + return z; +}//SubVector +//wrapper function +cdouble* SubVector(cdouble* x, int X1, int X, MList* List) +{ + return SubVector(0, x, X1, X, List); +}//SubVector + +//--------------------------------------------------------------------------- +/* + function transpose: matrix transpose: A'->A + + In: matrix a[N][N] + Out: matrix a[N][N] after transpose + + No return value. +*/ +void transpose(int N, double** a) +{ + double tmp; + for (int i=1; iZ + + In: matrix a[M][N] + Out: matrix z[N][M] + + Returns pointer to z. z is created anew if z=0 is specifid on start. +*/ +double** transpose(int N, int M, double** ta, double** a, MList* List) +{ + if (!ta) {Allocate2(double, N, M, ta); if (List) List->Add(ta, 2);} + for (int n=0; nAdd(P, 2);} + int sizeN=sizeof(double)*N; + for (int i=0; iAdd(P, 2); + return P; +}//Unitary +//wrapper functions +double** Unitary(int N, double* x, double* y, MList* List){return Unitary(N, 0, x, y, List);} +cdouble** Unitary(int N, cdouble* x, cdouble* y, MList* List){return Unitary(N, 0, x, y, List);} + + + diff -r 6422640a802f -r fc19d45615d1 matrix.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/matrix.h Tue Oct 05 11:04:40 2010 +0100 @@ -0,0 +1,407 @@ +#ifndef MatrixH +#define MatrixH + +/* + Matrix.cpp - matrix operations. + + Matrices are accessed by double pointers as MATRIX[Y][X], where Y is the row index. +*/ + +#include "xcomplex.h" +#include "arrayalloc.h" + +//--Similar balance---------------------------------------------------------- +void BalanceSim(int n, double** A); + +//--Choleski factorization--------------------------------------------------- +int Choleski(int N, double** L, double** A); + +//--matrix copy-------------------------------------------------------------- +double** Copy(int M, int N, double** Z, double** A, MList* List=0); + double** Copy(int M, int N, double** A, MList* List=0); + double** Copy(int N, double** Z, double ** A, MList* List=0); + double** Copy(int N, double ** A, MList* List=0); +cdouble** Copy(int M, int N, cdouble** Z, cdouble** A, MList* List=0); + cdouble** Copy(int M, int N, cdouble** A, MList* List=0); + cdouble** Copy(int N, cdouble** Z, cdouble** A, MList* List=0); + cdouble** Copy(int N, cdouble** A, MList* List=0); +double* Copy(int N, double* z, double* a, MList* List=0); + double* Copy(int N, double* a, MList* List=0); +cdouble* Copy(int N, cdouble* z, cdouble* a, MList* List=0); + cdouble* Copy(int N, cdouble* a, MList* List=0); + +//--matrix determinant calculation------------------------------------------- +double det(int N, double** A, int mode=0); +cdouble det(int N, cdouble** A, int mode=0); + +//--power methods for solving eigenproblems---------------------------------- +int EigPower(int N, double& l, double* x, double** A, double ep=1e-6, int maxiter=50); +int EigPowerA(int N, double& l, double* x, double** A, double ep=1e-6, int maxiter=50); +int EigPowerI(int N, double& l, double* x, double** A, double ep=1e-6, int maxiter=50); +int EigPowerS(int N, double& l, double* x, double** A, double ep=1e-6, int maxiter=50); +int EigPowerWielandt(int N, double& m, double* u, double l, double* v, double** A, double ep=1e-06, int maxiter=50); +int EigenValues(int N, double** A, cdouble* ev); +int EigSym(int N, double** A, double* d, double** Q); + +//--Gaussian elimination for solving linear systems-------------------------- +int GEB(int N, double* x, double** A, double* b); +int GESCP(int N, double* x, double** A, double*b); +void GExL(int N, double* x, double** L, double* a); +void GExLAdd(int N, double* x, double** L, double* a); +void GExL1(int N, double* x, double** L, double a); +void GExL1Add(int N, double* x, double** L, double a); + +/* + template GECP: Gaussian elimination with maximal column pivoting for solving linear system Ax=b + + In: matrix A[N][N], vector b[N] + Out: vector x[N] + + Returns 0 if successful. Contents of matrix A and vector b are destroyed on return. +*/ +templateint GECP(int N, T* x, Ta** A, T *b, Ta* logdet=0) +{ + if (logdet) *logdet=1E-302; int c, p, ip, *rp=new int[N]; for (int i=0; ifabs(A[rp[p]][i])) p=ip; ip++;} + if (A[rp[p]][i]==0) {delete[] rp; return 1;} + if (p!=i) {c=rp[i]; rp[i]=rp[p]; rp[p]=c;} + for (int j=i+1; j=0; i--) + { + x[i]=b[rp[i]]; for (int j=i+1; j + + In: vectors x[N], w[N] and y[N] + + Returns inner product of xw and y. +*/ +templatecdouble Inner(int N, Tx* x, Tw* w, cdouble* y) +{ + cdouble result=0; + for (int i=0; icdouble Inner(int N, Tx* x, Tw* w, double* y) +{ + cdouble result=0; + for (int i=0; i=N. + + In: matrix A[M][N], vector y[M] + Out: vector x[N] + + Returns the log determinant of AtA. Contents of matrix A and vector y are unchanged on return. +*/ +template T LSLinear(int M, int N, T* x, T** A, T* y) +{ + MList* mlist=new MList; + T** AtA=MultiplyXtX(N, M, A, mlist); + T* Aty=MultiplyXty(N, M, A, y, mlist); + T result; GECP(N, x, AtA, Aty, &result); + delete mlist; + return result; +}//LSLinear + +//--2-stage Least-square solution of overdetermined linear system------------ +void LSLinear2(int M, int N, double* x, double** A, double* y); + +//--LU factorization of a non-singular matrix-------------------------------- +int LU_Direct(int mode, int N, double* diag, double** a); +int LU(int N, double** l, double** u, double** a); void LU_DiagL(int N, double** l, double* diagl, double** u, double** a); +int LU_PD(int N, double** b); +int LU_PD(int N, double** b, double* c); +double LUCP(double **a, int N, int *ind, int& parity, int mode=1); + +//--LU factorization method for solving a linear system---------------------- +void LU(int N, double* x, double** A, double* y, int* ind=0); + +//--find maximum of vector--------------------------------------------------- +int maxind(double* data, int from, int to); + +//--matrix linear combination------------------------------------------------ +/* + template MultiAdd: matrix linear combination Z=X+aY + + In: matrices X[M][N], Y[M][N], scalar a + Out: matrix Z[M][N] + + Returns pointer to Z. Z is created anew if Z=0 is specified on start. +*/ +template Tz** MultiAdd(int M, int N, Tz** Z, Tx** X, Ty** Y, Ta a, MList* List=0) +{ + if (!Z){Allocate2(Tz, M, N, Z); if (List) List->Add(Z, 2);} + for (int i=0; i Tz* MultiAdd(int N, Tz* z, Tx* x, Ty* y, Ta a, MList* List=0) +{ + if (!z){z=new Tz[N]; if (List) List->Add(z, 1);} + for (int i=0; i Tx* MultiAdd(int N, Tx* x, Ty* y, Ta a, MList* List=0) +{ + return MultiAdd(N, (Tx*)0, x, y, a, List); +}//MultiAdd + +//--matrix multiplication by constant---------------------------------------- +/* + template Multiply: matrix-constant multiplication Z=aX + + In: matrix X[M][N], scalar a + Out: matrix Z[M][N] + + Returns pointer to Z. Z is created anew if Z=0 is specified on start. +*/ +template Tz** Multiply(int M, int N, Tz** Z, Tx** X, Ta a, MList* List=0) +{ + if (!Z){Allocate2(Tz, M, N, Z); if (List) List->Add(Z, 2);} + for (int i=0; i Tz* Multiply(int N, Tz* z, Tx* x, Ta a, MList* List=0) +{ + if (!z){z=new Tz[N]; if (List) List->Add(z, 1);} + for (int i=0; iTx* Multiply(int N, Tx* x, Ta a, MList* List=0) +{ + return Multiply(N, (Tx*)0, x, a, List); +}//Multiply + +//--matrix multiplication operations----------------------------------------- +/* + macro Multiply_full: matrix-matrix multiplication z=xy and multiplication-accumulation z=z+xy. + + Each expansion of the macro defines three function templates; two are named $MULTIPLY and do matrix + multiplication only; one is named $MULTIADD and accumulates the multiplicated result on top of a + specified matrix. One of the two $MULTIPLY functions allows using a pre-allocated matrix to accept + the matrix product, while the other directly allocates a new matrix and returns the pointer. + + Functions are named after their exact functions. For example, MultiplyXYc multiplies matrix X with + the complex conjugate of matrix Y, where postfix "c" attched to Y stands for conjugate. Likewise, + the postfix "t" stands for transpose, and "h" stnads for Hermitian (conjugate transpose). + + Three dimension arguments are needed by each function template. The first and last of the three are + the number of rows and columns, respectively, of the product (output) matrix. The middle one is the + "other", common dimension of both multiplier matrices. +*/ +#define Multiply_full(MULTIPLY, MULTIADD, xx, yy) \ + templateTx** MULTIPLY(int N, int M, int K, Tx** z, Tx** x, Ty** y, MList* List=0){ \ + if (!z) {Allocate2(Tx, N, K, z); if (List) List->Add(z, 2);} \ + for (int n=0; nTx** MULTIPLY(int N, int M, int K, Tx** x, Ty** y, MList* List=0){ \ + Tx** Allocate2(Tx, N, K, z); if (List) List->Add(z, 2); \ + for (int n=0; nvoid MULTIADD(int N, int M, int K, Tx** z, Tx** x, Ty** y){ \ + for (int n=0; nT** MULTIPLY(int N, T** z, T** x, T** y, MList* List=0){ \ + if (!z){Allocate2(T, N, N, z); if (List) List->Add(z, 2);} \ + if (z!=x) MULTIPLY(N, N, N, z, x, y); else{ \ + T* tmp=new T[N]; int sizeN=sizeof(T)*N; for (int i=0; iT** MULTIPLY(int N, T** x, T** y, MList* List=0){return MULTIPLY(N, N, N, x, y, List);}\ + templatevoid MULTIADD(int N, T** z, T** x, T** y){MULTIADD(N, N, N, z, x, y);} +Multiply_square(MultiplyXY, MultiAddXY) + +/* + macro Multiply_xx: matrix self multiplication z=xx and self-multiplication-accumulation z=z+xx. + + Each expansion of the macro defines three function templates; two are named $MULTIPLY and do matrix + multiplication only; one is named $MULTIADD and accumulates the multiplicated result on top of a + specified matrix. One of the two $MULTIPLY functions allows using a pre-allocated matrix to accept + the matrix product, while the other directly allocates a new matrix and returns the pointer. +*/ +#define Multiply_xx(MULTIPLY, MULTIADD, xx1, xx2, zzt) \ + templateT** MULTIPLY(int M, int N, T** z, T** x, MList* List=0){ \ + if (!z){Allocate2(T, M, M, z); if (List) List->Add(z, 2);} \ + for (int m=0; mT** MULTIPLY(int M, int N, T ** x, MList* List=0){ \ + T** Allocate2(T, M, M, z); if (List) List->Add(z, 2); \ + for (int m=0; mvoid MULTIADD(int M, int N, T** z, T** x){ \ + for (int m=0; m -#include +#include #include "procedures.h" #include "matrix.h" #include "opt.h" -#include "SinEst.h" +#include "sinest.h" //--------------------------------------------------------------------------- //TGMM methods diff -r 6422640a802f -r fc19d45615d1 quickspec.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/quickspec.cpp Tue Oct 05 11:04:40 2010 +0100 @@ -0,0 +1,349 @@ +//--------------------------------------------------------------------------- + +#include +#include +#include "quickspec.h" + + +//--------------------------------------------------------------------------- +/* + method TQuickSpectrogram::TQuickSpectrogram: + + In: AParent: pointer argument for calling G, if G is specified + AnId: integer argument for calling G, if G is specified + G: pointer to a function that supplies buffers used for FFT, 0 by default + Ausex: set if complete complex spectrogram is to be buffered and accessible + Auseph: set if phase spectrogram is to be buffered and accessible +*/ +__fastcall TQuickSpectrogram::TQuickSpectrogram(void* AParent, int AnId, bool Ausex, bool Auseph, GetBuf G) +{ + memset(this, 0, sizeof(TQuickSpectrogram)); + Parent=AParent; + Id=AnId; + usex=Ausex; + useph=Auseph; + GetFFTBuffers=G; + BufferSize=QSpec_BufferSize; + fwt=wtRectangle; + Wid=1024; + Offst=512; +}//TQuickSpectrogram + +//TQuickSpectrogram::~TQuickSpectrogram +__fastcall TQuickSpectrogram::~TQuickSpectrogram() +{ + FreeBuffers(); + free8(fw); + free8(fwin); + free(fhbi); +}//~TQuickSpectrogram + +//--------------------------------------------------------------------------- +/* + method TQuickSpectrogram::A: accesses amplitude spectrogram by frame + + In: fr: frame index, 0-based + + Returns pointer to amplitude spectrum of the fr'th frame, NULL if N/A +*/ +QSPEC_FORMAT* __fastcall TQuickSpectrogram::A(int fr) +{ + if (Capacity==0) SetFrCapacity((DataLength-Wid)/Offst+2); + if (fr<0 || fr>=Capacity) return NULL; + if (Frame[fr]<0 || !Valid[fr]) CalculateSpectrum(fr); + return fA[Frame[fr]]; +}//A + +//--------------------------------------------------------------------------- +/* + method TQuickSpectrogram::AddBuffer: increases internal buffer by BufferSize frames. Allocated buffers + beyond Capacity frames will not be indexed or used by TQuickSpectrogram. +*/ +void TQuickSpectrogram::AddBuffer() +{ + int base=1, Dim=Wid/2+1; + if (usex) base+=2; + if (useph) base+=1; + QSPEC_FORMAT* newbuffer=(QSPEC_FORMAT*)malloc(sizeof(QSPEC_FORMAT)*Dim*BufferSize*base); + int fr0=BufferCount*BufferSize; + for (int i=0; i*)&newbuffer[(BufferSize+i*2)*Dim], base+=2; + if (useph) fPh[fr]=&newbuffer[(BufferSize*base+i)*Dim]; + } + else break; + } + BufferCount++; +}//AddBuffer + +/* + method TQuickSpectrogram::AddBuffer: increase internal buffer by a multiple of BufferSize so that + it will be enough to host another AddFrCount frames. +*/ +void TQuickSpectrogram::AddBuffer(int AddFrCount) +{ + while (FrCount+AddFrCount>BufferSize*BufferCount) AddBuffer(); +}//AddBuffer + +//--------------------------------------------------------------------------- +/* + function IntToDouble: copy content of integer array to double array + + In: in: pointer to integer array + BytesPerSample: number of bytes each integer takes + Count: size of integer array, in integers + Out: vector out[Count]. + + No return value. +*/ +void IntToDouble(double* out, void* in, int BytesPerSample, int Count) +{ + if (BytesPerSample==1){unsigned char* in8=(unsigned char*)in; for (int k=0; k* lX=usex?fSpec[realfr]:NULL; + //choose the buffer actually used for FFT - use lX if it is specified as complex double array + //because it saves unnecessary data copying operations + cdouble *lx=(usex && sizeof(QSPEC_FORMAT)==sizeof(double))?(cdouble*)lX:x; + + //Actual FFT + if (fr*Offst+Wid<=DataLength) + ::CalculateSpectrum(&((char*)Data)[fr*Offst*BytesPerSample], BytesPerSample, win, fA[realfr], lph, Wid, w, lx, hbi); + else + ::CalculateSpectrum(&((char*)Data)[fr*Offst*BytesPerSample], BytesPerSample, win, fA[realfr], lph, Wid, DataLength-fr*Offst, w, x, hbi); + + //optional data copy from x to lX + if (usex && lx==x) for (int i=0; i=Capacity) fr2=Capacity-1; + for (int fr=fr1; fr<=fr2; fr++) if (Frame[fr]>=0) Valid[fr]=false, result++; + } + return result; +}//Invalidate + +//--------------------------------------------------------------------------- +/* + method TQuickSpectrogram::Ph: accesses phase spectrogram by frame + + In: fr: frame index, 0-based + + Returns pointer to phase spectrum of the fr'th frame, NULL if N/A +*/ +QSPEC_FORMAT* __fastcall TQuickSpectrogram::Ph(int fr) +{ + if (Capacity==0) SetFrCapacity((DataLength-Wid)/Offst+2); + if (fr<0 || fr>=Capacity) return NULL; + if (Frame[fr]<0 || !Valid[fr]) CalculateSpectrum(fr); + return fPh[Frame[fr]]; +}//Ph + +//--------------------------------------------------------------------------- +/* + method TQuickSpectrogram::SetFrCapacity: sets the capacity, i.e. the maximal number of frames handled + by this TQuickSpectrogram. + + In: AnFrCapacity: the new Capacity, in frames + + This method should not be called to set Capacity to a smaller value. +*/ +void TQuickSpectrogram::SetFrCapacity(int AnFrCapacity) +{ + //adjusting the size of index and validity arrays + Frame=(int*)realloc(Frame, sizeof(int)*AnFrCapacity); + Valid=(int*)realloc(Valid, sizeof(int)*AnFrCapacity); + + // + fA=(QSPEC_FORMAT**)realloc(fA, sizeof(QSPEC_FORMAT*)*AnFrCapacity); + if (usex) fSpec=(cmplx**)realloc(fSpec, sizeof(cmplx*)*AnFrCapacity); + if (useph) fPh=(QSPEC_FORMAT**)realloc(fPh, sizeof(QSPEC_FORMAT*)*AnFrCapacity); + if (AnFrCapacity>Capacity) + { + memset(&Frame[Capacity], 0xFF, sizeof(int)*(AnFrCapacity-Capacity)); + memset(&Valid[Capacity], 0x00, sizeof(int)*(AnFrCapacity-Capacity)); + + if (Capacity*)(&thisbuffer[(BufferSize+lfr*2)*Dim]), base+=2; + if (useph) fPh[fr]=&thisbuffer[(BufferSize*base+lfr)*Dim]; + } + else break; + } + } + } + Capacity=AnFrCapacity; +}//SetFrCapacity + +//--------------------------------------------------------------------------- +/* + method TQuickSpectrogram::Ph: accesses complex spectrogram by frame + + In: fr: frame index, 0-based + + Returns pointer to complex spectrum of the fr'th frame, NULL if N/A +*/ +cmplx* __fastcall TQuickSpectrogram::Spec(int fr) +{ + if (Capacity==0) SetFrCapacity((DataLength-Wid)/Offst+2); + if (fr<0 || fr>=Capacity) return NULL; + if (Frame[fr]<0 || !Valid[fr]) CalculateSpectrum(fr); + return fSpec[Frame[fr]]; +}//Spec + + diff -r 6422640a802f -r fc19d45615d1 quickspec.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/quickspec.h Tue Oct 05 11:04:40 2010 +0100 @@ -0,0 +1,158 @@ +#ifndef QuickSpecH +#define QuickSpecH + +/* + QuickSpec.cpp - TQuickSpectrogram class + + TQuickSpectrogram implements a compute-on-request spectrogram class. Every time one frame of the + spectrogram is read from this class, it checks if the single-frame spectrogram has been computed + already, computes it if not, and return the pointer to the spectrum. + + Further reading: "A buffering technique for real-time spectrogram displaying.pdf" +*/ + + +#include +#include +#include "xcomplex.h" +#include "windowfunctions.h" +#include "fft.h" +//--------------------------------------------------------------------------- + +#define QSPEC_FORMAT float //default spectral data format +#define QSpec_BufferSize 1024 //default initial buffer size, in frames, of TQuickSpectrogram + + +/* + __int24 is a 24bit signed integer type and __pint24 is its pointer type. Although __int24* will also + return a pointer to an __int24 structure, operations based on __int24* may have unspecified results, + depending on structure alignments imposed by compiler. It is therefore necessary to have an explicit + pointer type __pint24 to enforce 24-bit data alighment. + + Using __int24: + When storage format is not a concern, __int24 can be used the same way as __int16 or __int32. However, + a default 32-bit compiler may fail to implement compact 24-bit alignment to entries of an __int24[] + array. If 24-bit alignment is desired, then always create the array dynamically with new[], which + returns a __pint24 type pointer. Assigning a __pint24 type pointer to __int24* type variable should + be avoided. +*/ + +#ifndef INT24 +#define INT24 +struct __int24; +struct __pint24 +{ + char* p; + __fastcall __pint24(){} + __fastcall __pint24(const void* ap){p=(char*)ap;} + __pint24& __fastcall operator=(const void* ap){p=(char*)ap; return *this;} + __int24& __fastcall operator*(){return *(__int24*)p;} + __int24& __fastcall operator[](int index){return *(__int24*)&p[3*index];} + __pint24 __fastcall operator++(int){__pint24 result=*this; p+=3; return result;} + __pint24& __fastcall operator++(){p+=3; return *this;} + __pint24 __fastcall operator--(int){__pint24 result=*this; p-=3; return result;} + __pint24& __fastcall operator--(){p-=3; return *this;} + __pint24& __fastcall operator+=(int a){p+=3*a; return *this;} + __pint24& __fastcall operator-=(int a){p-=3*a; return *this;} + __fastcall operator void*() const{return p;} +}; +struct __int24 +{ + __int16 loword; + __int8 hibyte; + __fastcall __int24(){} + __fastcall __int24(const __int32 a){loword=*(__int16*)&a; hibyte=((__int16*)&a)[1];} + __fastcall __int24(const double f){__int32 a=f; loword=*(__int16*)&a; hibyte=((__int16*)&a)[1];} + __int24& __fastcall operator=(const __int32 a){loword=*(__int16*)&a; hibyte=((__int16*)&a)[1]; return *this;} + __int24& __fastcall operator=(const double f){__int32 a=f; loword=*(__int16*)&a; hibyte=((__int16*)&a)[1]; return *this;} + __fastcall operator __int32() const{__int32 result; *(__int16*)&result=loword; ((__int16*)&result)[1]=hibyte; return result;} + __pint24 operator &(){return (__pint24)this;} + void* operator new[](size_t count){void* result=malloc(3*count); return result;} + void operator delete[](void* p){free(p);} +}; +#endif + +/* + TQuickSpectrogram is a spectrogram class the handles the computation and storage of a spectrogram. + + Using TQuickSpectrogram: + + TQuickSpectrogram provides read-only access to the spectrogram of a given waveform. The spectrogram + contains a sequence of windowed Fourier transforms, computed from uniformly placed frames. The 0th + frame starts at 0 (inclusive) and finishes at Wid (exclusive). Each spectrum has Wid/2+1 entries. + + Follow these steps: + 1. create a QuickSpectrogram, specifying usex and useph, and optionally, external buffer provide G + and its arguments Id and Parent; + 2. set Data, DataLength and BytesPerSample; + 3. set frame size and hop size Wid and Offst; + 4. if G is not specified, set window type (optional extra parameter) for computing spectra; + 5. access the spectrogram via A(fr), Spec(fr) (optional) and Ph(fr) (optional). + Steps 2~4 do not have to follow the given order. + + Call Invalidate() to notify the object of changes of waveform content. + Call FreeBuffers() to return the object to the initial state before step 2. +*/ + +typedef void (*GetBuf)(int Id, cdouble* &w, cdouble* &x, double* &win, int* &hbi, void* Parent); +class TQuickSpectrogram +{ + int BufferCount; //number of buffers in use + int BufferSize; //number of frames each additional buffer holds + int FrCount; //number of allocated frames + + //internal storage of spectrogram + QSPEC_FORMAT** fPh; //phase spectrogram, optional + QSPEC_FORMAT** fA; //amplitude spectrogram, compulsory + cmplx** fSpec; //complete complex spectrogram, optional + + //internal buffers (optional) for FFT + WindowType fwt; //type of window + int fWid; //size of window + int* fhbi; //half-size bit-inversed integer table + double fwdp; //additional parameter specifying window type + double* fwin; //internal window + cdouble* fw; //FFT twiddle factors + cdouble* fx; //FFT data buffer + + //x and ph create-time switch + bool usex; //set at create time if complex spectrogram is required + bool useph; //set at create time if phase spectrogram is required + + //internal methods + void AddBuffer(); + void AddBuffer(int AddFrCount); + void __fastcall CalculateSpectrum(int fr); + void SetFrCapacity(int AnFrCapacity); + +public: + //if specified, Parent is responsible to supply FFT buffers through GetFFTBuffers (optional) + int Id; //an identifier given at create time, used as argument for calling GetFFTBuffers() + void* Parent; //a pointer used as argument for calling GetFFTBuffers() + GetBuf GetFFTBuffers; //if specified, this supplies FFT buffers + + //index and validity arrays associated with internal storage + int Capacity; //size of $Frame[] and &Valid[], usually set to the total number of frames of the data + int* Frame; //indices to individual frames in internal storage + int* Valid; //validity tags to individual frames in internal storage + + WindowType WinType; //window type for computing spectrogram + double WinParam; //additional parameter specifying certain window types (Gaussian, Kaiser, etc.) + + void* Data; //pointer to waveform audio + int DataLength; //length of waveform audio, in samples + int BytesPerSample; //bytes per sample of waveform audio + + int Offst; //frame offset + int Wid; //frame size, the same as window size + + __fastcall TQuickSpectrogram(void* AParent, int AnId, bool Ausex, bool Auseph, GetBuf G); + __fastcall ~TQuickSpectrogram(); + + QSPEC_FORMAT* __fastcall A(int fr); //accesses amplitude spectrogram at frame fr + void FreeBuffers(); //discards all computed frames and free memory + int Invalidate(int From, int To); //discards computed frames + QSPEC_FORMAT* __fastcall Ph(int fr); //accesses phase spectrogram at frame fr + cmplx* __fastcall Spec(int fr); //accesses complex spectrogram at frame fr +}; +#endif diff -r 6422640a802f -r fc19d45615d1 sinest.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sinest.cpp Tue Oct 05 11:04:40 2010 +0100 @@ -0,0 +1,3970 @@ +//--------------------------------------------------------------------------- + +#include +#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 (k1K2) 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 (k1K2) 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 (k1K2) 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=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; lFr, 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; lFr, 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; kx=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; lFr, 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; lL, 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; lL, 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; lL, 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=p.N/2) p.k2=p.N/2-1; + tmp=IPWindow(lf, &p); + if (minp=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=p.N/2) p.k2=p.N/2-1; + tmp=IPWindow(lf, &p); + if (minp=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) + { + 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; frsdip), 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=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=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=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; i0 && 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; n0 && 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; k0 && 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; kx=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; kf1, 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; kf1, 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) 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; i6) 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; n0.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; i1) + { + 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; fr0.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; i0.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; frAmp[mpf]) mpf=k; + if (mpf>pf-4 && mpfabuf[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; frabuf[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=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; i1) lastdif=dif; + dif=0; + if (iter==1) + { + for (int fr=0; frfabs(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; frfabs(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)1 && fabs(dif-lastdif)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=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=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=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=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=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=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=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; kM_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 , 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=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 + 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 over the lth frame + cdouble* ls=&s[l*T]; for (int i=0; i over the lth frame + cdouble *ls1=&s[l*T], *ls2=&s[l*T+T]; + for (int i=0; i=- + if (ds) + { + cdouble* lds=&ds[l*T]; + for (int i=0; i + //cdouble* ls=&s[l*T]; + //cdouble lsv2=Inner(2*T, ls, dv[i]); + dsv1[l*I+i]=lsv-sv[l][i]; //i.e. =-+dsv1[lI+i] + } + + //error check: srv[l]*pq= + for (int i=0; i over the lth frame + cdouble* ls=&s[0]; for (int i=0; i over the lth frame + for (int i=0; i=- + if (ds) + { + cdouble* lds=&ds[0]; + for (int i=0; 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. =-+dsv1[lI+i] + } + + //error check: srv[l]*pq= + for (int i=0; i over the lth frame + cdouble* ls=&s[(L-1)*T]; for (int i=0; i over the lth frame + for (int i=0; i=- + if (ds) + { + cdouble* lds=&ds[(L-1)*T]; + for (int i=0; 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. =-+dsv1[lI+i] + } + + //error check: srv[l]*pq= + for (int i=0; i + 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 over the lth frame + cdouble* ls=&s[l*T]; for (int i=0; i over the lth frame + cdouble *ls1=&s[l*T], *ls2=&s[l*T+T]; + for (int i=0; i over the lth frame + cdouble* ls=&s[0]; for (int i=0; i over the lth frame + for (int i=0; i over the lth frame + cdouble* ls=&s[(L-1)*T]; for (int i=0; i over the lth frame + for (int i=0; iaita= + double** Allocate2L(double, L_1*I*2, Np+Nq, AM, mlist); + for (int l=0; lAdd(pq, 1); + double* b=new double[2*L_1*I]; for (int i=0; i equals -, dsv2[I] tests that *pq= + +*/ +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 + //cdouble* ls=&s[l*T]; + dsv1[i]=lsv-svl[i]; //i.e. =-+dsv1[lI+i] + //sv[l][i]=lsv; + } + //error check: srv[l]*pq= + for (int i=0; i +*/ +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 over the lth frame + cdouble* ls=&s[l*T]; + for (int i=0; i + 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 over the lth frame + cdouble* ls=&s[l*T]; for (int i=0; i over the lth frame + cdouble *ls1=&s[l*T], *ls2=&s[l*T+T]; + for (int i=0; i=- and srv[l]*pq= + 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 - over the lth frame + cdouble* ls=&s[0]; for (int i=0; i over the lth frame + for (int i=0; i=- and srv[l]*pq= + 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 - over the lth frame + cdouble* ls=&s[(L-1)*T]; for (int i=0; i over the lth frame + for (int i=0; i=- and srv[l]*pq= + 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 aita= + double** Allocate2L(double, L_1*I*2, Np+Nq, AM, mlist); + for (int l=0; lAdd(pq, 1); + double* b=new double[2*L_1*I]; for (int i=0; iAdd(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; lAdd(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; lAdd(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; t1){dhm=dh[1]; for (int t=0; t0) 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; mAdd(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; lAdd(win, 1); + for (int l=1; lAdd(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 +#include "xcomplex.h" +#include "arrayalloc.h" +#include "matrix.h" +#ifdef I +#undef I +#endif + +//--since function derivative------------------------------------------------ +double ddsincd_unn(double x, int N); +double dsincd_unn(double x, int N); + +//--window spectrum and derivatives------------------------------------------ +cdouble* Window(cdouble* x, double f, int N, int M, double* c, int K1, int K2); +void dWindow(cdouble* dx, cdouble* x, double f, int N, int M, double* c, int K1, int K2); +void ddWindow(cdouble* ddx, cdouble* dx, cdouble* x, double f, int N, int M, double* c, int K1, int K2); + +//--spectral projection routines--------------------------------------------- +cdouble IPWindowC(double f, cdouble* x, int N, int M, double* c, double iH2, int K1, int K2); + +double IPWindow(double f, cdouble* x, int N, int M, double* c, double iH2, int K1, int K2, bool returnamplitude); +double IPWindow(double f, void* params); +double ddIPWindow(double f, void* params); +double ddIPWindow(double f, cdouble* x, int N, int M, double* c, double iH2, int K1, int K2, double& dipwindow, double& ipwindow); + +double sIPWindow(double f, int L, cdouble** x, int N, int M, double* c, double iH2, int K1, int K2, cdouble* ej2ph=0); +double sIPWindow(double f, void* params); +double dsIPWindow(double f, int L, cdouble** x, int N, int M, double* c, double iH2, int K1, int K2, double& sip); +double dsIPWindow(double f, void* params); +double ddsIPWindow(double f, int L, cdouble** x, int N, int M, double* c, double iH2, int K1, int K2, double& dsip, double& sip); +double ddsIPWindow(double f, void* params); +double ddsIPWindow_unn(double f, cdouble* x, int N, int M, double* c, int K1, int K2, double& dsipwindow, double& sipwindow, cdouble* w_unn=0); + +double sIPWindowC(double f, int L, double offst_rel, cdouble** x, int N, int M, double* c, double iH2, int K1, int K2, cdouble* ej2ph=0); +double sIPWindowC(double f, void* params); +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); +double dsIPWindowC(double f, void* params); +double ddsIPWindowC(double f, int L, double offst_rel, cdouble** x, int N, int M, double* c, double iH2, int K1, int K2, double& dsip, double& sip); +double ddsIPWindowC(double f, void* params); + +//--least-square sinusoid estimation routines-------------------------------- +double LSESinusoid(cdouble* x, int N, double B, int M, double* c, double iH2, double& a, double& pp, double epf=1e-6); +void LSESinusoid(double& f, cdouble* x, int N, double B, int M, double* c, double iH2, double& a, double& pp, double epf=1e-6); +double LSESinusoid(int f1, int f2, cdouble* x, int N, double B, int M, double* c, double iH2, double& a, double& pp, double epf); +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); +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); + +//--multi-sinusoid spectral projection routines------------------------------ +void IPMulti(int I, double* f, cdouble* lmd, cdouble* x, int Wid, int K1, int K2, int M, double* c, double eps=0); +void IPMulti(int I, double* f, cdouble* lmd, cfloat* x, int Wid, int K1, int K2, int M, double* c, double eps=0, double* sens=0, double* r1=0); +void IPMultiSens(int I, double* f, int Wid, int K1, int K2, int M, double* c, double* sens, double eps=0); +double IPMulti(int I, double* f, cdouble* lmd, cdouble* x, int Wid, int M, double* c, double iH2, int B); +double IPMulti_Direct(int I, double* f, double* ph, double* a, cdouble* x, int Wid, int M, double* c, double iH2, int B); +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=0, double** Q=0); +cdouble* IPMulti(int I, int J, double* f, double* ph, double* a, cdouble* x, int Wid, int M, double* c, cdouble** wt=0, cdouble** Q=0, double** L=0, MList* RetList=0); + +//--dual-sinusoid spectral projection routines------------------------------- +double WindowDuo(double df, int N, double* d, int M, cdouble* w); +double ddWindowDuo(double df, int N, double* d, int M, double& dwindow, double& window, cdouble* w); +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); +double sIPWindowDuo(double f2, void* params); +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); +double ddsIPWindowDuo(double f2, void* params); +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); + +//--time-frequency reassignment---------------------------------------------- +void TFReas(double& f, double& t, double& fslope, int Wid, cdouble* data, double* win, double* dwin, double* ddwin, double* plogaslope=0); +void TFReas(double& f, double t, double& a, double& ph, double& fslope, int Wid, cdouble* data, double* w, double* dw, double* ddw, double* win=0); + +//--additive and multiplicative reestimation routines------------------------ +typedef double (*TBasicAnalyzer)(double* fs, double* as, double* phs, double* das, cdouble* x, int Count, int Wid, int Offst, __int16* ref, int reserved, bool LogA); +void AdditiveUpdate(double* fs, double* as, double* phs, double* das, cdouble* x, int Count, int Wid, int Offst, TBasicAnalyzer BasicAnalyzer, int reserved, bool LogA=false); +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=false); +void MultiplicativeUpdate(double* fs, double* as, double* phs, double* das, cdouble* x, int Count, int Wid, int Offst, TBasicAnalyzer BasicAnalyzer, int reserved, bool LogA=false); +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=false); +void MultiplicativeUpdateF(double* fs, double* as, double* phs, __int16* x, int Fr, int frst, int fren, int Wid, int Offst); + +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=0); +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); +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=0); +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=0); + +//--local derivative algorithms - DAFx09------------------------------------- +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); +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=false); +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=false); + +//--the Abe-Smith estimator-------------------------------------------------- +void TFAS05(double& f, double& t, double& a, double& ph, double& aesp, double& fslope, int Wid, double* data, double* w, double res=1); +void TFAS05_enh(double& f, double& t, double& a, double& ph, double& aesp, double& fslope, int Wid, double* data, double* w, double res=1); +void TFAS05_enh(double& f, double& t, double& a, double& ph, int Wid, double* data, double* w, double res=1); + +//--piecewise derivative algorithms and tools-------------------------------- +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=0, cdouble* ds=0); +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=0, cdouble* ds=0); +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=0, cdouble* ds=0, double** dh=0); +void seth(int M, int T, double**& h, MList* mlist); +void setdh(int M, int T, double**& dh, MList* mlist); +void setdih(int M, int T, double**& dih, MList* mlist); +void setu(int I, int Wid, cdouble**& u, cdouble**& du, int WinOrder=2, MList* mlist=0); +void ssALinearSpline(int L, int T, int M, int& N, double*** &A, MList* mlist, int mode=0); +void ssACubicHermite(int L, int T, int M, int& N, double*** &A, MList* mlist, int mode=0); +void ssACubicSpline(int L, int T, int M, int& N, double*** &A, MList* mlist, int mode=0); +void ssLinearSpline(int L, int T, int M, int &N, double** &h, double*** &A, MList* mlist, int mode=0); +void ssCubicHermite(int L, int T, int M, int& N, double** &h, double*** &A, MList* mlist, int mode=0); +void ssCubicSpline(int L, int T, int M, int& N, double** &h, double*** &A, MList* mlist, int mode=0); +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=0, int WinOrder=2, int I=2, int endmode=0, cdouble* ds=0); +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=2, int I=2, int endmode=0, cdouble* ds=0); +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=2, int I=2, int endmode=0, cdouble* ds=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); + +//--local derivative algorithms - general------------------------------------ +/* + template DerivativeLSv: local derivative algorithm for estimating time-varying sinusoids, "v" version, + i.e. using tuned test functions. + + In: s[Wid]: waveform data + v[I][Wid], dv[I][Wid]: test functions and their derivatives + h[M+1][Wid]: basis functions + p0[p0s], q0[q0s]: zero-constraints, i.e. Re(lmd[p0[*]]) and Im(lmd[q0[*]]) are constrained zero. + Out: lmd[1:M]: coefficients of h[1:M]. + + Returns inner product of s and v[0]. +*/ +templatecdouble DerivativeLSv(int Wid, Ts* s, int I, cdouble** v, cdouble** dv, int M, double **h, cdouble* lmd, int p0s, int* p0, int q0s, int* q0) +{ + int Kr=M*2-p0s-q0s; //number of real unknowns apart from p0 and q0 + if (I=0){uind[up]=p; ind[p]=up; up++;} p++;} + if (up!=Kr) throw(""); + } + + cdouble* sv1=new cdouble[I]; + for (int i=0; i=0) + { + A[2*i][lind]=shv.x; + A[2*i+1][lind]=shv.y; + } + if ((lind=ind[2*m-1])>=0) + { + A[2*i][lind]=-shv.y; + A[2*i+1][lind]=shv.x; + } + } + + double* pq=new double[Kr]; + if (2*I==Kr) GECP(Kr, pq, A, (double*)sv1); + else LSLinear(2*I, Kr, pq, A, (double*)sv1); + + memset(lmd, 0, sizeof(double)*(M+1)*2); + for (int k=0; kcdouble DerivativeLS(int Wid, Ts* s, int I, double omg, Tu** u, Tu** du, int M, double **h, cdouble* lmd, int p0s, int* p0, int q0s, int* q0) +{ + cdouble** Allocate2(cdouble, I, Wid, v); + cdouble** Allocate2(cdouble, I, Wid, dv); + cdouble jomg=cdouble(0, omg); int hWid=Wid/2; + for (int c=0; ccdouble DerivativeLS_AmpPh(int Wid, int M, double** integr_h, cdouble* lmd, double omg, Tu* u0, cdouble sv0) +{ + cdouble e0=0; double hWid=Wid/2.0; + for (int n=0; n300) expo.x=300; + else if (expo.x<-300) expo.x=-300; + e0+=exp(expo)**(cdouble(u0[n]).rotate(omg*(n-hWid))); + } + return log(sv0/e0); +}//DerivativeLS_AmpPh + +/* + template DerivativeLS_AmpPh: amplitude and phase estimation in the local derivative algorithm, "u" + version. + + In: s[Wid]: waveform data + u0[Wid], omg: base-band test function and carrier frequency used for computing v0[] + integr_h[M+1][Wid]: integrals of basis functions + + Returns coefficient to integr_h[0]=1. +*/ +templatecdouble DerivativeLS_AmpPh(int Wid, int M, double** integr_h, cdouble* lmd, double omg, Tu* u0, Ts* s) +{ + cdouble ss0=0, e0=0; double hWid=Wid/2.0; + for (int n=0; n300) expo.x=300; + else if (expo.x<-300) expo.x=-300; + e0+=~exp(expo)*abs(u0[n]); + ss0+=s[n]**exp(expo)*abs(u0[n]); + } + return log(ss0/e0); +}//DerivativeLS_AmpPh + +cdouble DerivativeLSv_AmpPh(int, int, double**, cdouble*, cdouble*, cdouble); //the "v" version is implemented as a normal function in SinEst.cpp. + +/* + template DerivativeLSv: local derivative algorithm for estimating time-varying sinusoids, "v" version. + + In: s[Wid]: waveform data + v[I][Wid], dv[I][Wid]: test functions and their derivatives + h[M+1][Wid], integr_h[M+1][Wid]: basis functions and their integrals + p0[p0s], q0[q0s]: zero-constraints, i.e. Re(lmd[p0[*]]) and Im(lmd[q0[*]]) are constrained zero. + Out: lmd[M+1]: coefficients of h[M+1], including lmd[0]. + + No return value. +*/ +template void DerivativeLSv(int Wid, Ts* s, int I, cdouble** v, cdouble** dv, int M, double **h, double **integr_h, cdouble* lmd, int p0s, int* p0, int q0s, int* q0) +{ + cdouble sv0=DerivativeLSv(Wid, s, I, v, dv, M, h, lmd, p0s, p0, q0s, q0); + lmd[0]=DerivativeLSv_AmpPh(Wid, M, integr_h, lmd, v[0], sv0); +}//DerivativeLSv_AmpPh + +/*template DerivativeLSv: local derivative algorithm for estimating time-varying sinusoids, "u" version. + + In: s[Wid]: waveform data + u[I][Wid], du[I][Wid]: base-band test functions and their derivatives + omg: angular frequency onto which u[I] and du[I] are modulated to give the test functions + h[M+1][Wid], integr_h[M+1][Wid]: basis functions and their integrals + p0[p0s], q0[q0s]: zero-constraints, i.e. Re(lmd[p0[*]]) and Im(lmd[q0[*]]) are constrained zero. + Out: lmd[M+1]: coefficients of h[M+1], including lmd[0]. + + No return value. +*/ +templatevoid DerivativeLS(int Wid, Ts* s, int I, double omg, Tu** u, Tu** du, int M, double **h, double **integr_h, cdouble* lmd, int p0s, int* p0, int q0s, int* q0) +{ + cdouble sv0=DerivativeLS(Wid, s, I, omg, u, du, M, h, lmd, p0s, p0, q0s, q0); + lmd[0]=DerivativeLS_AmpPh(Wid, M, integr_h, lmd, omg, u[0], s); //sv0); +}//DerivativeLSv + +/* + template CosineWindows: generates the Hann^(K/2) window and its L-1 derivatives as Result[L][Wid+1] + + In: K, L, Wid + Out: w[L][Wid+1]: Hann^(K/2) window function and its derivatives up to order L-1 + + Returns pointer to w. w is created anew if w=0 is specified on start. +*/ +templateT** CosineWindows(int K, int Wid, T **w, int L=0) +{ + if (L<=0) L=K; + if (!w) {Allocate2(T, L, Wid+1, w);} + memset(w[0], 0, sizeof(T)*L*(Wid+1)); + int hWid=Wid/2, dWid=Wid*2; + double *s=new double[dWid+hWid], *c=&s[hWid]; //s[n]=sin(pi*n/N), n=0, ..., 2N-1 + double *C=new double[K+2], *lK=&C[K/2+1], piC=M_PI/Wid; + //C[i]=C(K, i)(-1)^i*2^(-K+1), the combination number, i=0, ..., K/2 + //ik[i]=(K-2i)^k*(M_PI/Wid)^k, i=0, ..., K/2 + //calculate C(K,i)(-1)^i*2^(-K+1) + C[0]=1.0/(1<<(K-1)); double lC=C[0]; for (int i=1; i+i<=K; i++){lC=lC*(K-i+1)/i; C[i]=(i%2)?(-lC):lC;} + //calculate sin/cos functions + for (int n=0; n300) e=300; + if (e<-300) e=-300; + s[t]=exp(cdouble(e, ph+(t*t*(_q+t*_p)))); + ph+=dph; + } +}//SinusoidExpA + +/* +//This is not used any longer as the recursion does not seem to help saving computation with all its overheads. +void SinusoidExp(cdouble* data, int CountSt, int CountEn, double a3, double a2, double a1, double a0, + double omg3, double omg2, double omg1, double omg0, double &ea, double &ph, bool add) +{ + int i; + double dea, ddea, dddea, ddddea, + dph, ddph, dddph, ddddph, + sph, cph, sdph, cdph, sddph, cddph, sdddph, cdddph, sddddph, cddddph, + e0=ea, e1=a0, e2=0.5*a1, e3=a2/3, e4=a3/4, + p0=ph, p1=omg0, p2=0.5*omg1, p3=omg2/3, p4=omg3/4, tmp; + if (CountSt==0) + { + dea=e1+e2+e3+e4; ddea=2*e2+6*e3+14*e4; dddea=6*e3+36*e4; ddddea=24*e3; + dph=p1+p2+p3+p4; ddph=2*p2+6*p3+14*p4; dddph=6*p3+36*p4; ddddph=24*p4; + } + else + { + ea=e0+CountSt*(e1+CountSt*(e2+CountSt*(e3+CountSt*e4))); + dea=e1+e2+e3+e4+CountSt*(2*e2+3*e3+4*e4+CountSt*(3*e3+6*e4+CountSt*4*e4)); + ddea=2*e2+6*e3+14*e4+CountSt*(6*e3+24*e4+CountSt*12*e4); + dddea=6*e3+36*e4+CountSt*24*e4; ddddea=24*e4; + ph=p0+CountSt*(p1+CountSt*(p2+CountSt*(p3+CountSt*p4))); + dph=p1+p2+p3+p4+CountSt*(2*p2+3*p3+4*p4+CountSt*(3*p3+6*p4+CountSt*4*p4)); + ddph=2*p2+6*p3+14*p4+CountSt*(6*p3+24*p4+CountSt*12*p4); + dddph=6*p3+36*p4+CountSt*24*p4; ddddph=24*p4; + } + sph=sin(ph), cph=cos(ph); + sdph=sin(dph), cdph=cos(dph); + sddph=sin(ddph), cddph=cos(ddph); + sdddph=sin(dddph), cdddph=cos(dddph); + sddddph=sin(ddddph), cddddph=cos(ddddph); + if (add) + { + for (i=CountSt; i=xs[Fr-1] + add: specifies if the resynthesized sinusoid is to be added to or to replace the content of output buffer + Out: xrec[0:den-dst-1]: output buffer hosting synthesized sinusoid from dst to den. + phs[Fr]: phase angles at xs[Fr] + + Returns pointer to xrec. +*/ +double* SynthesizeSinusoid(double* xrec, int dst, int den, double* phs, int Fr, double* xs, double* fs, double* as, bool add, bool* terminatetag) +{ + double *f3=new double[Fr*8], *f2=&f3[Fr], *f1=&f3[Fr*2], *f0=&f3[Fr*3], + *a3=&f3[Fr*4], *a2=&a3[Fr], *a1=&a3[Fr*2], *a0=&a3[Fr*3]; + CubicSpline(Fr-1, f3, f2, f1, f0, xs, fs, 1, 1); + CubicSpline(Fr-1, a3, a2, a1, a0, xs, as, 1, 1); + double ph=phs[0]; + for (int fr=0; fr=xs[Fr-1] + add: specifies if the resynthesized sinusoid is to be added to or to replace the content of output + buffer + Out: xrecm[0:den-dst-1]: output buffer hosting synthesized sinusoid from dst to den. + + Returns pointer to xrecm. +*/ +double* SynthesizeSinusoidP(double* xrecm, int dst, int den, double* phs, int Fr, double* xs, double* fs, double* as, bool add) +{ + double *f3=new double[Fr*8], *f2=&f3[Fr], *f1=&f3[Fr*2], *f0=&f3[Fr*3], + *a3=&f3[Fr*4], *a2=&a3[Fr], *a1=&a3[Fr*2], *a0=&a3[Fr*3]; + CubicSpline(Fr-1, f3, f2, f1, f0, xs, fs, 1, 1); + CubicSpline(Fr-1, a3, a2, a1, a0, xs, as, 1, 1); + for (int fr=0; fr -#include +#include #include "vibrato.h" #include "arrayalloc.h" #include "fft.h" #include "hssf.h" -#include "Matrix.h" +#include "matrix.h" #include "splines.h" #include "xcomplex.h" //--------------------------------------------------------------------------- diff -r 6422640a802f -r fc19d45615d1 wavelet.cpp --- a/wavelet.cpp Tue Oct 05 10:45:57 2010 +0100 +++ b/wavelet.cpp Tue Oct 05 11:04:40 2010 +0100 @@ -1,7 +1,7 @@ //--------------------------------------------------------------------------- #include -#include +#include #include "wavelet.h" #include "matrix.h" diff -r 6422640a802f -r fc19d45615d1 windowfunctions.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/windowfunctions.cpp Tue Oct 05 11:04:40 2010 +0100 @@ -0,0 +1,377 @@ +//--------------------------------------------------------------------------- +#include +#include +#include "windowfunctions.h" +#include "align8.h" +//--------------------------------------------------------------------------- + +/* + function I0: Bessel function of order zero + + Returns the Bessel function of x. +*/ +double I0(double x) +{ + const double eps=1e-9; + + int n=1; + double S=1, D=1, T; + + while (D>eps*S) + { + T=x/(2*n++); + D*=T*T; + S+=D; + } + return S; +}//I0 + +/* + function FillWindow: fills a buffer $Result with a window function. + + In: wt:window type + Count: window size + ips & ups: extra window specificatin parameters + Out: newwindow[Count+1]: the window function. + + No return value. This function is designed assuming Count being even, and Count/2 is the symmetry + centre of newwindow. newwindow has physical size Count+1 for compatibility purpose. For all vanishing + windows (e.g. Hann) newwindow[0]=newwindow[Count]=0. +*/ +void FillWindow(double* Result, WindowType wt, int Count, int* ips, double* dps) +{ + switch(wt) + { + case wtRectangle: + for (int i=0; i<=Count; i++) + Result[i]=1; + break; + case wtTriangular: + for (int i=0; i<=Count; i++) + Result[i]=1-2*fabs(i-Count/2.0)/Count; + break; + case wtHamming: + for (int i=0; i<=Count; i++) + Result[i]=(0.54-0.46*cos(2*M_PI*i/Count)); + break; + case wtBlackman: + for (int i=0; i<=Count; i++) + Result[i]=0.42-0.5*cos(2*M_PI*i/Count)+0.08*cos(4*M_PI*i/Count); + break; + case wtGaussian: + { + double num=*dps*M_PI*M_PI/2/Count/Count; + for (int i=0; i<=Count; i++) + Result[i]=exp(-(i-Count/2.0)*(i-Count/2.0)*num); + break; + } + case wtKaiser: + { + double ldps=*dps*M_PI*M_PI/2/Count; + double den=I0(0.5*Count*ldps); + for (int i=0; i<=Count; i++) + Result[i]=I0(ldps*sqrt(0.25*Count*Count-(i-Count*0.5)*(i-Count*0.5)))/den; + break; + } + case wtHalfCosine: + { + for (int i=0; i<=Count; i++) + Result[i]=sin(M_PI*i/Count); + break; + } + case wtHann: + { + for (int i=0; i<=Count; i++) + Result[i]=(0.5-cos(M_PI*2*i/Count)/2); + break; + } + case wtHannSqr: + { + for (int i=0; i<=Count; i++) + Result[i]=(3-4*cos(M_PI*2*i/Count)+cos(M_PI*4*i/Count))/8; + break; + } + case wtHann3sqrt: + { + for (int i=0; i<=Count; i++) + { + double tmp=sin(M_PI*i/Count); + Result[i]=tmp*tmp*tmp; + } + break; + } + } +}//FillWindow + +/* + function NewWindow: creates a window function. + + In: wt: window type + Count: window size + ips & ups: extra window specificatin parameters + Out: newwindow[Count+1]: the window function. + + Returns pointer to newwindow. newwindow is created anew if newwindow=0 is specified on start. +*/ +double* NewWindow(WindowType wt, int Count, int* ips, double* dps, double* newwindow) +{ + double* Result=newwindow; if (!Result) Result=new double[Count+1]; + FillWindow(Result, wt, Count, ips, dps); + return Result; +}//NewWindow + +/* + function NewWindow8: 8-byte aligned version of NewWindow. + + In: wt: window type + Count: window size + ips & ups: extra window specificatin parameters + Out: newwindow[Count+1]: the window function. + + Returns pointer to newwindow. newwindow is created anew and 8-byte aligned if newwindow=0 is + specified on start. However, if newwindow is not 8-byte aligned on start, the unaligned buffer is + returned. +*/ +double* NewWindow8(WindowType wt, int Count, int* ips, double* dps, double* newwindow) +{ + double* Result=newwindow; if (!Result) Result=(double*)malloc8(sizeof(double)*(Count+1)); + FillWindow(Result, wt, Count, ips, dps); + return Result; +}//NewWindow8 + +/* + function NewdWindow: computes the derivative of a window function. + + In: wt: window type + Count: window size + ips & ups: extra window specificatin parameters + Out: newdwindow[Count+1]: the derivative window function. + + Returns pointer to newdwindow. newdwindow is created anew if newdwindow=0 is specified on start. +*/ +double* NewdWindow(WindowType wt, int Count, int* ips, double* dps, double* newdwindow) +{ + double* Result=newdwindow; if (!Result) Result=new double[Count+1]; + double piiCount=M_PI/Count; + switch(wt) + { + case wtRectangle: + memset(Result, 0, sizeof(double)*(Count+1)); + break; + case wtTriangular: + throw("Trying to differentiate triangular window."); + break; + case wtHamming: + for (int i=0; i<=Count; i++) + Result[i]=0.92*piiCount*sin(2*piiCount*i); + break; + case wtBlackman: + for (int i=0; i<=Count; i++) + Result[i]=piiCount*sin(2*piiCount*i)-0.32*piiCount*sin(4*piiCount*i); + break; + case wtGaussian: + throw("Trying to differentiate Gaussian window."); + break; + case wtKaiser: + throw("Trying to differentiate Kaiser window."); + break; + case wtHalfCosine: + { + for (int i=0; i<=Count; i++) + Result[i]=piiCount*cos(piiCount*i); + break; + } + case wtHann: + { + for (int i=0; i<=Count; i++) + Result[i]=piiCount*sin(2*piiCount*i); + break; + } + case wtHannSqr: + { + for (int i=0; i<=Count; i++) + Result[i]=piiCount*sin(2*piiCount*i)-0.5*piiCount*sin(4*piiCount*i); + break; + } + case wtHann3sqrt: + { + for (int i=0; i<=Count; i++) + { + double s=sin(M_PI*i/Count), c=cos(M_PI*i/Count); + Result[i]=3*piiCount*s*s*c; + } + } + } + return Result; +}//NewdWindow + +/* + function NewddWindow: computes the 2nd-order derivative of a window function. + + In: wt: window type + Count: window size + ips & ups: extra window specificatin parameters + Out: newddwindow[Count+1]: the 2nd-order derivative window function. + + Returns pointer to newddwindow. newddwindow is created anew if newddwindow=0 is specified on start. +*/ +double* NewddWindow(WindowType wt, int Count, int* ips, double* dps, double* newddwindow) +{ + double* Result=newddwindow; if (!Result) Result=new double[Count+1]; + double piiCount=M_PI/Count; + double piC2=piiCount*piiCount; + switch(wt) + { + case wtRectangle: + memset(Result, 0, sizeof(double)*(Count+1)); + break; + case wtTriangular: + throw("Trying to double-differentiate triangular window."); + break; + case wtHamming: + for (int i=0; i<=Count; i++) + Result[i]=1.84*piC2*cos(2*piiCount*i); + break; + case wtBlackman: + for (int i=0; i<=Count; i++) + Result[i]=2*piC2*cos(2*piiCount*i)-1.28*piC2*cos(4*piiCount*i); + break; + case wtGaussian: + throw("Trying to double-differentiate Gaussian window."); + break; + case wtKaiser: + throw("Trying to double-differentiate Kaiser window."); + break; + case wtHalfCosine: + { + for (int i=0; i<=Count; i++) + Result[i]=-piC2*sin(piiCount*i); + break; + } + case wtHann: + { + for (int i=0; i<=Count; i++) + Result[i]=2*piC2*cos(2*piiCount*i); + break; + } + case wtHannSqr: + { + for (int i=0; i<=Count; i++) + Result[i]=2*piC2*cos(2*piiCount*i)-2*piC2*cos(4*piiCount*i); + break; + } + case wtHann3sqrt: + { + for (int i=0; i<=Count; i++) + { + double s=sin(M_PI*i/Count), c=cos(M_PI*i/Count); + Result[i]=3*piC2*(2*c*c-s*s)*s; + } + break; + } + } + return Result; +}//NewddWindow + +/* + function NewdddWindow: computes the 3rd-order derivative of a window function. + In: wt: window type + Count: window size + ips & ups: extra window specificatin parameters + Out: newdddwindow[Count+1]: the 3rd-order derivative window function. + + Returns pointer to newdddwindow. newdddwindow is created anew if newdddwindow=0 is specified on start. +*/ +double* NewdddWindow(WindowType wt, int Count, int* ips, double* dps, double* newdddwindow) +{ + double* Result=newdddwindow; if (!Result) Result=new double[Count+1]; + double piiCount=M_PI/Count; + double piC2=piiCount*piiCount; + double piC3=piiCount*piC2; + switch(wt) + { + case wtRectangle: + memset(Result, 0, sizeof(double)*(Count+1)); + break; + case wtTriangular: + throw("Trying to triple-differentiate triangular window."); + break; + case wtHamming: + for (int i=0; i<=Count; i++) + Result[i]=-3.68*piC3*sin(2*piiCount*i); + break; + case wtBlackman: + for (int i=0; i<=Count; i++) + Result[i]=-4*piC3*sin(2*piiCount*i)+5.12*piC3*sin(4*piiCount*i); + break; + case wtGaussian: + throw("Trying to triple-differentiate Gaussian window."); + break; + case wtKaiser: + throw("Trying to triple-differentiate Kaiser window."); + break; + case wtHalfCosine: + { + for (int i=0; i<=Count; i++) + Result[i]=-piC3*cos(piiCount*i); + break; + } + case wtHann: + { + for (int i=0; i<=Count; i++) + Result[i]=-4*piC3*sin(2*piiCount*i); + break; + } + case wtHannSqr: + { + for (int i=0; i<=Count; i++) + Result[i]=-4*piC3*sin(2*piiCount*i)+8*piC3*sin(4*piiCount*i); + break; + } + case wtHann3sqrt: + throw("Trying to triple-differentiate Hann^1.5 window."); + break; + } + return Result; +}//NewdddWindow + +//--------------------------------------------------------------------------- +/* + function windowspec: computes a few descriptors of a cosine family window. A window function in the + cosine window family is the linear combination of a few cosine functions, therefore has a cosine + decomposition. + + In: wt: window type + N: window size + Out: c[M+1], coefficients of cosine decomposition + iH2: reciprocal of square of L2 norm, + d[2M+1]: self-convolution of c[], optional + + No return value. +*/ +void windowspec(WindowType wt, int N, int* M, double* c, double* iH2, double* d) +{ + switch(wt) + { + case wtRectangle: + M[0]=0, c[0]=1, iH2[0]=1.0/N/N; + if (d) d[0]=1; + break; + case wtHamming: + M[0]=1, c[0]=0.54, c[1]=0.23, iH2[0]=1.0/(0.3974*N*N); + if (d) d[0]=0.3974, d[1]=0.2484, d[2]=0.0529; + break; + case wtBlackman: + M[0]=2, c[0]=0.42, c[1]=0.25, c[2]=0.04, iH2[0]=1.0/(0.3046*N*N); + if (d) d[0]=0.3046, d[1]=0.23, d[2]=0.0961, d[4]=0.02, d[5]=0.0016; + break; + case wtHann: + M[0]=1, c[0]=0.5, c[1]=0.25, iH2[0]=1.0/(0.375*N*N); + if (d) d[0]=0.375, d[1]=0.25, d[2]=0.0625; + break; + default: + M[0]=1, c[0]=0.5, c[1]=0.25, iH2[0]=1.0/(0.375*N*N); + if (d) d[0]=0.375, d[1]=0.25, d[2]=0.0625; + break; + } +}//windowspec diff -r 6422640a802f -r fc19d45615d1 windowfunctions.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/windowfunctions.h Tue Oct 05 11:04:40 2010 +0100 @@ -0,0 +1,33 @@ +#ifndef WindowFunctionsH +#define WindowFunctionsH + +/* + WindowFunctions.cpp - implements a few common window functions. +*/ + +enum WindowType +{ + wtRectangle, + wtTriangular, + wtHamming, + wtBlackman, + wtGaussian, + wtKaiser, + wtHalfCosine, + wtHann, + wtHannSqr, + wtHann3sqrt +}; + +//--window function computation routines------------------------------------- +void FillWindow(double* newwindow, WindowType wt, int Count, int* ips=0, double* dps=0); +double* NewWindow(WindowType wt, int Count, int* ips=0, double* dps=0, double* newwindow=0); +double* NewWindow8(WindowType wt, int Count, int* ips=0, double* dps=0, double* newwindow=0); +double* NewdWindow(WindowType wt, int Count, int* ips=0, double* dps=0, double* newdwindow=0); +double* NewddWindow(WindowType wt, int Count, int* ips=0, double* dps=0, double* newddwindow=0); +double* NewdddWindow(WindowType wt, int Count, int* ips=0, double* dps=0, double* newdddwindow=0); + +//--other functions---------------------------------------------------------- +void windowspec(WindowType wt, int N, int* M, double* c, double* iH2, double* d=0); + +#endif