HarmonicFinder.c

Go to the documentation of this file.
00001 /*
00002 *  Copyright (C) 2007 Jolien Creighton
00003 *
00004 *  This program is free software; you can redistribute it and/or modify
00005 *  it under the terms of the GNU General Public License as published by
00006 *  the Free Software Foundation; either version 2 of the License, or
00007 *  (at your option) any later version.
00008 *
00009 *  This program is distributed in the hope that it will be useful,
00010 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00011 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012 *  GNU General Public License for more details.
00013 *
00014 *  You should have received a copy of the GNU General Public License
00015 *  along with with program; see the file COPYING. If not, write to the
00016 *  Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston,
00017 *  MA  02111-1307  USA
00018 */
00019 
00020 /*----------------------------------------------------------------------- 
00021  * 
00022  * File Name: HarmonicFinder.c
00023  * 
00024  * Author: Sintes, A. M.
00025  * 
00026  * Revision: $Id: 
00027  * 
00028  *----------------------------------------------------------------------- 
00029  * 
00030  * NAME 
00031  *  HarmonicFinder.c
00032  * 
00033  * SYNOPSIS 
00034  *
00035  *
00036  * DESCRIPTION 
00037  *   Given certain harmonic indices (k)  finds the frequency interval
00038  *   locations (in bins) of the interference (around k*fLine)
00039  * 
00040  * DIAGNOSTICS 
00041  *
00042  * CALLS
00043  * 
00044  * NOTES
00045  * 
00046  *
00047  *-----------------------------------------------------------------------
00048  */
00049 
00050 /************************************ <lalVerbatim file="HarmonicFinderCV">
00051 Author: Sintes, A. M. 
00052 $Id: HarmonicFinder.c,v 1.5 2008/07/28 17:03:09 cristina Exp $
00053 ************************************* </lalVerbatim> */
00054 
00055 /* <lalLaTeX>
00056 
00057 \subsection{Module \texttt{HarmonicFinder.c}}
00058 \label{ss:HarmonicFinder.c}
00059  Given certain harmonic indices $\{ k\} $  finds the frequency interval
00060    location (in bins) of the interference (around $k\times f_0$).
00061 
00062 \subsubsection*{Prototypes}
00063 \vspace{0.1in}
00064 \input{HarmonicFinderD}
00065 \idx{LALHarmonicFinder()}
00066 
00067 \subsubsection*{Description}
00068 This routine determines the lower and upper frequency limit (in bins)
00069 of each harmonic line considered, $(\nu_{ik}, \nu_{fk})$, from the power
00070 spectrum.
00071 
00072 The harmonic indices  are given as an input \verb@*in1@.
00073 \begin{description}
00074 \item[\texttt{in1->length}] Number of harmonics.
00075 \item[\texttt{in1->data}]   List of harmonics to consider, e.g., 
00076        $\{ k\} $ =  $\{ 3, 5, 9, 11 \ldots\}$
00077 \end{description}
00078 
00079 The power spectrum, $\vert\tilde x(\nu)\vert^2$, together with the approximate
00080 frequency $f_0$ (in Hz) of the interference fundamental harmonic and the 
00081 frequency
00082 resolution are also given as an input  \verb@*in2@.
00083 \begin{description}
00084 \item[\texttt{in2->length}] The number of elements in \texttt{in2->data}.
00085 \item[\texttt{in2->data}]   The spectrum,  $\vert\tilde x(\nu)\vert^2$.
00086 \item[\texttt{in2->deltaF}] The $\Delta$F offset between samples (in Hz).
00087 \item[\texttt{in2->fLine}]  The interference fundamental frequency $f_0$ 
00088               (in Hz), e.g., 60 Hz.
00089 \end{description}
00090 
00091 The  output  \verb@*out@ is a vector whose length is 
00092 \verb@out->length@ = $3\times$~\verb@in1->length@,
00093  and contains  for each considered harmonic, in the following order,
00094  its index $k$ and the bin location of $\nu_{ik}$ and  $\nu_{fk}$.
00095 \begin{description}
00096 \item[\texttt{out->length}] The number of elements in \texttt{out->data}.
00097 \item[\texttt{out->data}]    $\{ k,\nu_{ik}, \nu_{fk} \} $,
00098       e.g.,  $\{$3, 9868, 9894, 5, 16449, 16487, 9, 29607, 29675$\ldots\}$.
00099 \end{description}
00100 
00101 
00102 
00103 
00104 \subsubsection*{Algorithm}
00105 
00106 It looks for the location of interference harmonics assuming that
00107 the fundamental harmonic is located somewhere in the interval
00108 \verb@in2->fLine@$ - 0.7$ Hz and \verb@in2->fLine@$+ 0.7$ Hz.
00109 First, the power spectrum is smoothed by averaging neighboring bins.
00110 Then, the corresponding frequency  intervals
00111 of the harmonics considered are reduced by finding the central
00112 bin position of the lines and their standard deviation. This is done
00113 using the smooth power spectrum as a probability density distribution.
00114 The limits of the lines are set initially  at 1 or 2 sigma from the
00115 central bin location and, later, they are moved until they hit a local
00116  minimum in a selected interval.
00117 See the code for details.
00118 
00119 \subsubsection*{Uses}
00120 \begin{verbatim}
00121 LALSCreateVector()
00122 LALSDestroyVector()
00123 \end{verbatim}
00124 
00125 \subsubsection*{Notes}
00126 
00127 \vfill{\footnotesize\input{HarmonicFinderCV}}
00128 
00129 </lalLaTeX> */
00130 
00131 
00132 
00133 #include <math.h>
00134 #include <lal/LALConstants.h>
00135 #include <lal/CLR.h>
00136 
00137 #define MIN(A, B)       ((A) < (B) ? (A) : (B))
00138 #define MAX(A, B)       ((A) > (B) ? (A) : (B))
00139 
00140 #define log2( x )       ( log( x ) / LAL_LN2 )
00141 
00142 NRCSID (HARMONICFINDERC, "$Id: HarmonicFinder.c,v 1.5 2008/07/28 17:03:09 cristina Exp $");
00143 
00144 
00145 /* <lalVerbatim file="HarmonicFinderD"> */
00146 void LALHarmonicFinder (LALStatus  *status,
00147          INT4Vector         *out,   /* harmonic index and location, size 3*l */
00148          REAL4FVectorCLR    *in2,   /* |x(f)|^2, data + information */
00149          INT4Vector         *in1)   /* the harmonic index, size l */
00150 { /* </lalVerbatim> */
00151 
00152   INT4    n,l;
00153   INT4    k,binini,binfin;
00154   INT4    nInf1s,nInf2s,nSup1s,nSup2s;
00155   INT4    nBins;
00156   INT4    *kv;
00157   INT4    *kf;
00158 
00159   INT4    i,j;
00160 
00161   REAL4   devF,fL,myfmax;
00162   REAL4   Tobs;
00163   
00164   REAL8   sumpx,mean1,std1,mn2,sn2;
00165   REAL4   llindar,cc,invk,norma;
00166   
00167   REAL4   sInf1,sInf2,sSup1,sSup2;
00168 
00169   REAL4        *px;
00170   REAL4Vector  *pxs  = NULL;
00171     
00172 /* --------------------------------------------- */
00173 
00174   INITSTATUS (status, "LALHarmonicFinder", HARMONICFINDERC);
00175   ATTATCHSTATUSPTR (status); 
00176 
00177   /*   Make sure the arguments are not NULL: */ 
00178   ASSERT (out, status, CLRH_ENULL, CLRH_MSGENULL);
00179   ASSERT (in1, status, CLRH_ENULL, CLRH_MSGENULL);
00180   ASSERT (in2, status, CLRH_ENULL, CLRH_MSGENULL);
00181 
00182   /*   Make sure the data pointers are not NULL: */ 
00183   ASSERT (out->data, status, CLRH_ENULL, CLRH_MSGENULL);
00184   ASSERT (in1->data, status, CLRH_ENULL, CLRH_MSGENULL);
00185   ASSERT (in2->data, status, CLRH_ENULL, CLRH_MSGENULL);
00186 
00187   /*   Make sure that the size is correct:  */
00188   ASSERT (out->length > 0, status, CLRH_ESIZE, CLRH_MSGESIZE);
00189   ASSERT (in2->length > 2, status, CLRH_ESIZE, CLRH_MSGESIZE);
00190 
00191   /*   Make sure that the lengths are correct (size mismatch): */  
00192   ASSERT (3 *in1->length == out->length, status, CLRH_ESZMM, CLRH_MSGESZMM);
00193 
00194 
00195    /*  Make sure F_max > fLine  */ 
00196   ASSERT (fabs(1.01*  in2->fLine) <  fabs(in2->deltaF *(in2->length - 1) ), 
00197                status, CLRH_EFREQ, CLRH_MSGEFREQ); 
00198 
00199   /*   Make sure deltaF!= 0 */
00200   ASSERT (fabs(in2->deltaF) != 0, status, CLRH_EFREQ, CLRH_MSGEFREQ); 
00201 
00202   /* -------------------------------------------   */
00203  
00204   devF = 0.7;
00205   /*fL = fabs( in2->fLine);*/
00206   if (in2->fLine < 0)
00207     fL=-1*in2->fLine;
00208   else
00209     fL=in2->fLine;
00210   
00211   
00212   px = in2->data;
00213   n  = in2->length;
00214 
00215   l  = in1->length;
00216   kv = in1->data;
00217   kf = out->data;
00218 
00219   Tobs = fabs(1.0 / in2->deltaF );
00220   myfmax = fabs(in2->deltaF) *(n - 1.0);
00221  
00222   /* create extra vectors */
00223   TRY(LALSCreateVector(status->statusPtr, &pxs,  n), status);
00224  
00225  /* -------------------------------------------   */
00226   /* smoothing the spectrum by averaging neighboring bins */
00227   /* ignoring border effects */
00228 
00229   nBins = 1;
00230   if (Tobs > 1.0 )
00231     { nBins = ceil ( log2(Tobs)) ;  }
00232   
00233   /* a normalization to control overflow */
00234   norma = 1.0/( (2.0*n -2.0)*(2.0*nBins +1.0)  );
00235   
00236   /* Border effects */
00237   sumpx = 0.0;
00238   for ( i=0; i<= 2* nBins; ++i)
00239     { sumpx += px[i];}
00240 
00241   for (i=0; i<= nBins; ++i )
00242     { pxs->data[i] = sumpx*norma;  }
00243   
00244   /* intermediate values */
00245   for (i=nBins+1; i< n-nBins; ++i)
00246     { pxs->data[i] = pxs->data[i-1] + (px[i+nBins] - px[i-nBins-1])*norma; }
00247   
00248   /* the other border */
00249   for (i=n-nBins; i<n; ++i)
00250     { pxs->data[i] = pxs->data[i-1];}
00251 
00252   /* Added new hack, doesn't change weighted mean or weighted variances */
00253   /* Cristina Torres Thu-Jun-26-2008:200806261728 */
00254   norma=pxs->data[0];
00255   for (i=1;i<n;i++)
00256     if (norma>=pxs->data[i])
00257       norma=pxs->data[i];
00258   if (norma < 0)
00259     {
00260       norma=(-1*norma)+1;
00261       for (i=0;i<n;i++)
00262         pxs->data[i]=pxs->data[i]+norma;
00263     }
00264   /* End new hack */
00265 
00266   /* -------------------------------------------   */
00267 
00268   /* the first line */
00269   
00270   /* k = fabs(*kv);  */
00271   
00272   k= kv[0];
00273   if ( k < 0 ) { k = -k; }
00274   
00275   binini = floor( k*( fL - devF)*Tobs );
00276   binfin = ceil(  k*( fL + devF)*Tobs );
00277 
00278   ASSERT ( k != 0, status, CLRH_EFREQ, CLRH_MSGEFREQ); 
00279   ASSERT ( binfin <  n, status, CLRH_EFREQ, CLRH_MSGEFREQ); 
00280   ASSERT ( fL > devF, status, CLRH_EFREQ, CLRH_MSGEFREQ); 
00281 
00282   sumpx = 0.0;
00283   mean1 = 0.0;
00284   std1  = 0.0;
00285   for (i=binini; i<= binfin; ++i) {
00286     sumpx += pxs->data[i]; /* sum of the distribution, normalize it */
00287     mean1 += i*pxs->data[i]; 
00288   }
00289   mean1 = mean1/sumpx;   /* central point of the first line considered */
00290   
00291   /* separated loops due to precision problems */
00292   for (i=binini; i<= binfin; ++i) {
00293     std1  += (i-mean1)*(i-mean1)*pxs->data[i]; 
00294   }
00295   std1 = sqrt( std1/sumpx );      /* std of the line */
00296   
00297   invk = 1.0/k;
00298   
00299   /* -------------------------------------------   */
00300   
00301   /* for all the  lines */
00302   llindar = 1.1;
00303   cc = 4.0;
00304   
00305   for (j=0; j<l; ++j) {
00306     /* k = fabs( kv[j] ); */ 
00307     
00308     k = kv[j];
00309     if ( k < 0 ) { k = -k; }
00310     binini = floor( k*(mean1 - std1*cc)*invk );
00311     binfin = ceil ( k*(mean1 + std1*cc)*invk );
00312 
00313     ASSERT ( binfin <  n, status, CLRH_EFREQ, CLRH_MSGEFREQ); 
00314 
00315     kf[3*j] = k;
00316     
00317     sumpx = 0.0;
00318     mn2 = 0.0;
00319     sn2 = 0.0;
00320     
00321     for (i=binini; i<= binfin; ++i) {
00322       sumpx += pxs->data[i]; /* sum of the distribution, normalize it */
00323       mn2 += i*pxs->data[i]; 
00324     }
00325     mn2 = mn2/sumpx;   /* central point of the first line considered */
00326     
00327     
00328     /* separated loops due to precision problems */
00329     for (i=binini; i<= binfin; ++i) {
00330       sn2 += (i- mn2)*(i- mn2)*pxs->data[i]; 
00331     }
00332     
00333     sn2 = sqrt( sn2/sumpx );      /* std of the line */
00334     
00335     /* initial settings for the limits */
00336     nInf1s= MAX(binini, floor(mn2-  sn2 ) );
00337     nInf2s= MAX(binini, floor(mn2-2*sn2 ) );
00338     
00339     nSup1s= MIN(binfin, ceil(mn2+  sn2 ) );
00340     nSup2s= MIN(binfin, ceil(mn2+2*sn2 ) );
00341     
00342     /* shifting from 1 sigma to 2 sigma if there is a big difference */
00343     /* and setting closer intervals where there is no big difference */
00344     sInf1 = 0.0;
00345     sInf2 = 0.0;
00346     sSup1 = 0.0;
00347     sSup2 = 0.0;
00348    
00349     for (i=0; i<= nBins; ++i) {
00350       sInf1 += pxs->data[nInf1s -i];
00351       sInf2 += pxs->data[nInf2s -i];
00352       sSup1 += pxs->data[nSup1s +i];
00353       sSup2 += pxs->data[nSup2s +i];
00354     }  
00355     
00356     if (sInf1/sInf2 > llindar ) 
00357       {  nInf1s = nInf2s;  }
00358     else
00359       {  binini = nInf2s; } 
00360     
00361     
00362     if (sSup1/sSup2 > llindar)
00363       {  nSup1s = nSup2s; }
00364     else
00365       {  binfin = nSup2s; }
00366     
00367     /* move to the next local minimum in the selected interval*/
00368     
00369     i=nInf1s;
00370     while ( i>binini ) {
00371       if ( pxs->data[i] < pxs->data[i-1])
00372         break;
00373       --i;
00374     }
00375     nInf1s = i;
00376     kf[3*j+1] = nInf1s;
00377     
00378     i=nSup1s;
00379     while ( i<binfin ) {
00380       if ( pxs->data[i] < pxs->data[i+1])
00381         break;
00382       ++i;
00383     }
00384     nSup1s = i;
00385     kf[3*j+2] = nSup1s;
00386     
00387   } /* closes loop of all lines */
00388   
00389   /* -------------------------------------------   */
00390   
00391   /* Destroy Vectors  */
00392   TRY(LALSDestroyVector(status->statusPtr, &pxs), status);
00393   
00394   /* -------------------------------------------   */
00395   
00396   DETATCHSTATUSPTR (status);
00397   
00398   /* normal exit */
00399   RETURN (status);
00400 }
00401 
00402 #undef MIN
00403 #undef MAX

Generated on Sun Oct 12 02:31:56 2008 for LAL by  doxygen 1.5.2