[xiph-commits] r13310 - trunk/ghost/libghost

jm at svn.xiph.org jm at svn.xiph.org
Wed Jul 25 05:10:32 PDT 2007


Author: jm
Date: 2007-07-25 05:10:32 -0700 (Wed, 25 Jul 2007)
New Revision: 13310

Modified:
   trunk/ghost/libghost/sinusoids.c
Log:
Improved non-linear optimisation by not restarting the linear part at zero
for each non-linear iteration.


Modified: trunk/ghost/libghost/sinusoids.c
===================================================================
--- trunk/ghost/libghost/sinusoids.c	2007-07-25 12:10:16 UTC (rev 13309)
+++ trunk/ghost/libghost/sinusoids.c	2007-07-25 12:10:32 UTC (rev 13310)
@@ -71,7 +71,7 @@
          }
       }
       //printf ("%f ", sinusoidism[tmp_id]);
-      if (sinusoidism[tmp_id]<60)
+      if (sinusoidism[tmp_id]<50)
       {
          *N=i;
          break;
@@ -255,8 +255,13 @@
    for (i=0;i<N;i++)
       w0[i] = w[i];
    
+   for (i=0;i<N;i++)
+      A[i] = dA[i] = phi[i] = dw[i] = 0;
+   for (i=0;i<N;i++)
+      ai[i] = bi[i] = ci[i] = di[i] = 0;
+   
    /* Iterate on the non-linear part (frequency) a couple times */
-   for (nonlin=0;nonlin<5;nonlin++)
+   for (nonlin=0;nonlin<3;nonlin++)
    {
    /* Build a table for the four basis functions at each frequency: cos(x), sin(x), x*cos(x), x*sin(x)*/
    for (i=0;i<N;i++)
@@ -266,7 +271,8 @@
       float rotR, rotI;
       rotR = cos(w[i]);
       rotI = sin(w[i]);
-      /* Computing sin/cos table using complex rotations */
+      /* Computing sin/cos table using complex rotations.
+         Only need to compute the tables for half the length because of the symmetry.*/
       cos_table[i][0] = cos(.5*w[i]);
       sin_table[i][0] = sin(.5*w[i]);
       for (j=1;j<L2;j++)
@@ -277,8 +283,8 @@
          cos_table[i][j] = re;
          sin_table[i][j] = im;
       }
-      /* Only need to compute the tables for half the length because of the symmetry.
-         Eventually, we'll have to replace the cos/sin with rotations */
+      /* Compute energy of basis functions. There may be a closed-form solution for that
+         or we could tabulate it. */
       for (j=0;j<L2;j++)
       {
          float jj = j+.5;
@@ -315,19 +321,30 @@
    for (j=0;j<len;j++)
       e[j] = x[j];
    /* Split the error into a symmetric component and an anti-symmetric component. 
-      This speeds everything up by a factor of 2 */
+   This speeds everything up by a factor of 2 */
    for (j=0;j<L2;j++)
    {
       sym[j] = e[j+L2]+e[L2-j-1];
       anti[j] = e[j+L2]-e[L2-j-1];
    }
-   
+
+   /* Start the linear optimisation where we left last time */
    for (i=0;i<N;i++)
-      ai[i] = bi[i] = ci[i] = di[i] = 0;
-   int tata=0;
-   /* This is an iterative linear solution -- much quicker than inverting a matrix */
-   for (iter=0;iter<5;iter++)
    {
+      ai[i] = A[i]*cos(phi[i]);
+      bi[i] = -A[i]*sin(phi[i]);
+      ci[i] = dA[i]*cos(phi[i]);
+      di[i] = -dA[i]*sin(phi[i]);
+      for (j=0;j<L2;j++)
+         sym[j] -= (2*ai[i])*cos_table[i][j];
+      for (j=0;j<L2;j++)
+         anti[j] -= (2*ai[i])*sin_table[i][j];
+   }
+   
+   /* This is an iterative linear solution -- much quicker than inverting a matrix.
+      It's pretty much the Gauss-Seidel algorithm */
+   for (iter=0;iter<2;iter++)
+   {
       for (i=0;i<N;i++)
       {
          float tmp1=0, tmp2=0;
@@ -375,20 +392,30 @@
    for (j=0;j<len;j++)
       y[j] = x[j]-e[j];
 
+   /* Update real sinusoid parameters */
    for (i=0;i<N;i++)
    {
       //float A, phi, dA, dw;
       A[i] = sqrt(ai[i]*ai[i] + bi[i]*bi[i]);
-      phi[i] = atan2(bi[i], ai[i]);
-      //phi = ai[i]*ai[i] + bi[i]*bi[i];
+      if (fabs(ai[i])+fabs(bi[i])<.01)
+         phi[i] = 0;
+      else
+         phi[i] = atan2(-bi[i], ai[i]);
       dA[i] = (ci[i]*ai[i] + bi[i]*di[i])/(.01f+A[i]);
       dw[i] = (ci[i]*bi[i] - di[i]*ai[i])/(.01f+A[i]*A[i]);
       //printf ("%f %f %f %f %f %f %f %f %f\n", w[i], ai[i], bi[i], ci[i], di[i], A, phi, dA, dw);
-      w[i] = w[i] + .4*dw[i];
+      /* Update the frequency with only a fraction of the dw term to prevent instabilities */
+      w[i] = w[i] + .5*dw[i];
+      /* Make sure we didn't deviate too much from the original frequency */
       if (w[i] > w0[i]+.025)
          w[i] = w0[i]+.025;
       if (w[i] < w0[i]-.025)
          w[i] = w0[i]-.025;
+      //Prevent stupid frequencies (i.e. outsite of ]0,pi[
+      if (w[i] < .002)
+         w[i] = .002;
+      if (w[i] > M_PI-.01)
+         w[i] = M_PI-.01;
       //if (nonlin == 4)
       //   printf("%d %f %f %f %f %f %f %f %f %f %f\n", count, w[i], ai[i], bi[i], ci[i], di[i], A[i], phi[i], dA[i], dw[i], w0[i]);
    }



More information about the commits mailing list