• API Main Page
  • Documentation
  • Modules
  • Data Structures
  • Files
  • File List
  • Globals

src/time_frequency.c

Go to the documentation of this file.
00001 /***************************************************************************
00002  *   Copyright (C) 2008 by Matthias Ihrke   *
00003  *   mihrke@uni-goettingen.de   *
00004  *                                                                         *
00005  *   This program is free software; you can redistribute it and/or modify  *
00006  *   it under the terms of the GNU General Public License as published by  *
00007  *   the Free Software Foundation; either version 2 of the License, or     *
00008  *   (at your option) any later version.                                   *
00009  *                                                                         *
00010  *   This program is distributed in the hope that it will be useful,       *
00011  *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
00012  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
00013  *   GNU General Public License for more details.                          *
00014  *                                                                         *
00015  *   You should have received a copy of the GNU General Public License     *
00016  *   along with this program; if not, write to the                         *
00017  *   Free Software Foundation, Inc.,                                       *
00018  *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
00019  ***************************************************************************/
00020 
00021 #include "time_frequency.h"
00022 #include "linalg.h"
00023 
00038 Spectrogram* spectrogram( const Array *sig, Spectrogram *spectgram, 
00039                                   OptArgList *optargs ){
00040   double x;
00041   void *ptr;
00042   double sample_frequency;
00043   WindowFunction winfct; 
00044   int winlength;
00045   double winparam;
00046   int N_freq;
00047   int N_time;
00048   double corner_freqs[2];
00049   int *timepoints;
00050 
00051   /* check input */
00052   bool isvec;
00053   vector_CHECK( isvec, sig );
00054   if( !isvec ) return NULL;
00055 
00056   int n=sig->size[0];
00057   /* defaults */
00058   sample_frequency = 500.0;
00059   winfct = window_hanning;
00060   winlength =  MAX( SQR( sqrt(next_pow2( n ))-3 ), 5 );
00061   winparam=0.0;
00062   N_freq = winlength*4;
00063   N_time = n;
00064   corner_freqs[0] = 0.0;
00065   corner_freqs[1] = 250.0;
00066   timepoints = NULL;
00067   bool N_time_set=FALSE;
00068 
00069   /* get params */
00070   optarg_PARSE_SCALAR( optargs, "sample_frequency", sample_frequency, double, x );
00071   optarg_PARSE_PTR( optargs, "winfct", winfct, WindowFunction, ptr );
00072   optarg_PARSE_SCALAR( optargs, "winlength", winlength, int, x );
00073   optarg_PARSE_SCALAR( optargs, "winparam", winparam, double, x );
00074   optarg_PARSE_SCALAR( optargs, "N_freq", N_freq, int, x );
00075   if( optarglist_has_key( optargs, "N_time" ) ){
00076      x = optarglist_scalar_by_key( optargs, "N_time" );
00077      if( !isnan( x ) ){
00078         N_time=(int)x;
00079         N_time_set=TRUE;
00080      }
00081   }
00082   if( optarglist_has_key( optargs, "corner_freqs" ) ){
00083      ptr = optarglist_ptr_by_key( optargs, "corner_freqs" );
00084      if( ptr ){
00085         corner_freqs[0] = ((double*)ptr)[0];
00086         corner_freqs[1] = ((double*)ptr)[1];
00087      }
00088   }
00089   if( optarglist_has_key( optargs, "timepoints" ) ){
00090      ptr = optarglist_ptr_by_key( optargs, "timepoints" );
00091      if( ptr && N_time_set ){
00092         timepoints = (int*)ptr;
00093      }
00094   }
00095 
00096   dprintf("got sfreq=%f, winfct=%p, winlength=%i, winparam=%f, N_f=%i,"
00097              "N_t=%i, cf=(%f,%f), timepoints=%p\n",
00098              sample_frequency, winfct, winlength, winparam, N_freq, N_time, 
00099              corner_freqs[0], corner_freqs[1], timepoints );
00100 
00101   Array *window=winfct( winlength, winparam );
00102 
00103   spectgram = spectrogram_stft( sig, sample_frequency, 
00104                                           window, N_freq, N_time, corner_freqs, 
00105                                           timepoints, spectgram );
00106   return spectgram;
00107 }
00108 
00109 
00144 Spectrogram* spectrogram_stft(const Array* sig, double sampling_rate,
00145                                         const Array *Window, int N_freq, int N_time, 
00146                                         double corner_freqs[2], 
00147                                         int *timepoints, Spectrogram *spectgram){
00148 
00149   int            Nfft, timepoint, frequency, time;
00150   int            taumin, taumax, tau;
00151   int            half_Window_Length;
00152   double        *wind_sig_complex;      /* windowed signal */
00153   double         normh;
00154   double         inter;
00155   int            corner_freqs_idx[2]; /* nearest sample in discretized setting */
00156   int            N_freq_spect;    /* number of frequencies in spectrgram */
00157   int            Window_Length;
00158 
00159   /* check for 1D and DOUBLE */
00160   bool isvec;
00161   vector_CHECK( isvec, sig );
00162   if( !isvec ) return NULL;
00163   vector_CHECK( isvec, Window );
00164   if( !isvec ) return NULL;
00165   
00166   int n=sig->size[0];
00167   Window_Length=Window->size[0];
00168 
00169   /* normalizing to [0, 100] */
00170   half_Window_Length = (Window_Length - 1) / 2;
00171   inter = 0.0;
00172   for (frequency = 0; frequency <Window_Length; frequency++){
00173      inter += SQR (vec_IDX(Window,frequency));
00174   }
00175   normh = sqrt (inter);
00176 
00177   /* FFT-settings */
00178   Nfft = pow( 2, next_pow2( N_freq ));    /* num of samples for FFT */
00179   if( corner_freqs[1]<=corner_freqs[0] || 
00180         corner_freqs[0]<0 || corner_freqs[1]>sampling_rate/2.0 ){
00181      errprintf("corner_freqs funny: (%f,%f)\n", 
00182                   corner_freqs[0], corner_freqs[1] );
00183      return NULL;
00184   }
00185   corner_freqs_idx[0] = (int)round( (corner_freqs[0]/(sampling_rate/2.0)) * (N_freq-1) );
00186   corner_freqs_idx[1] = (int)round( (corner_freqs[1]/(sampling_rate/2.0)) * (N_freq-1) );
00187   dprintf(" Corner-freqs=(%.2f,%.2f) in idx=(%i,%i)\n", corner_freqs[0], corner_freqs[1],
00188              corner_freqs_idx[0], corner_freqs_idx[1] );
00189   dprintf(" Returning actual frequencies: (%.3f, %.3f)\n", 
00190              (corner_freqs_idx[0]/(double)N_freq)*sampling_rate/2.0, 
00191              (corner_freqs_idx[1]/(double)N_freq)*sampling_rate/2.0 ); 
00192   N_freq_spect = corner_freqs_idx[1]-corner_freqs_idx[0];
00193   
00194 
00195   /*                memory allocation for the windowed signal           */
00196   wind_sig_complex = (double *) calloc (2*Nfft, sizeof (double));
00197 
00198   if( spectgram==NULL ){
00199      spectgram = spectrogram_init( N_freq_spect, N_time );
00200   }
00201   spectgram->low_corner_freq = corner_freqs[0];
00202   spectgram->up_corner_freq  = corner_freqs[1];
00203 
00204   /* computation of the fft for the current windowed signal */
00205   for (timepoint = 0; timepoint < N_time; timepoint++) {
00206      /* initialization of the intermediary vector */
00207      for (frequency = 0; frequency < 2*Nfft; frequency++){
00208         wind_sig_complex[frequency] = 0.0;
00209      }
00210 
00211      /* current time to compute the stft */
00212      if( timepoints ){
00213         time = timepoints[timepoint];
00214      } else {
00215         time = timepoint*(int)(n/N_time);
00216      }
00217      /* dprintf( "Spectrum at sample '%i'\n", time ); */
00218 
00219      /* the signal is multipied by the window between the instants
00220          time-taumin and time+taumax 
00221         when the window is wider than the number of desired frequencies (tfr.N_freq),
00222          the range is limited to tfr.N_freq */
00223      taumin = MIN (N_freq / 2, half_Window_Length);
00224      taumin = MIN (taumin, time);
00225 
00226      taumax = MIN ((N_freq / 2 - 1), half_Window_Length);
00227      taumax = MIN (taumax, (n - time - 1));
00228 
00229      /* dprintf(" tau = (%i, %i)\n", taumin, taumax); */
00230      /* The signal is windowed around the current time */
00231      frequency=0;
00232      for (tau = -taumin; tau <= taumax; tau++){
00233         wind_sig_complex[2*frequency  ] = vec_IDX(sig,time + tau) *
00234           vec_IDX( Window, half_Window_Length + tau ) / normh;
00235         wind_sig_complex[2*frequency+1] = 0.0;
00236         frequency++;
00237      }
00238      /* fft of the windowed signal */
00239      fft( wind_sig_complex, Nfft, 1 );  
00240      /* gsl_fft_complex_radix2_forward ( wind_sig_complex, 1, Nfft );  */
00241 
00242      /* the first half of the fft is put in the stft matrix  */
00243      for (frequency = corner_freqs_idx[0]; frequency < corner_freqs_idx[1]; frequency++){
00244         spectgram->sgram[timepoint][frequency].re = wind_sig_complex[2*frequency  ];
00245         spectgram->sgram[timepoint][frequency].im = wind_sig_complex[2*frequency+1];
00246      }
00247   } /* for t */
00248 
00249  /*--------------------------------------------------------------------*/
00250   free (wind_sig_complex);
00251 
00252   return spectgram;
00253 }
00254 
00255 
00264 Array* spectrogram_powerspectrum( const Spectrogram *s ){
00265   int i,j;
00266   Array *p = array_new2( DOUBLE, 2, s->N_time, s->N_freq );
00267   
00268   for( i=0; i<s->N_time; i++ ){
00269      for( j=0; j<s->N_freq; j++ ){
00270         mat_IDX( p, i,j) = SQR( complex_abs( s->sgram[i][j] ) );
00271      }
00272   }
00273   return p;
00274 }
00275 
00282 Spectrogram* spectrogram_init( int N_freq, int N_time ){
00283   Spectrogram *s;
00284   int i;
00285   
00286   dprintf("N_freq=%i, N_time=%i\n", N_freq, N_time );
00287   s = (Spectrogram*) malloc( sizeof(Spectrogram) );
00288   s->samplingrate = 500.0;
00289   s->N_freq = N_freq;
00290   s->N_time = N_time;
00291   s->low_corner_freq=0;
00292   s->up_corner_freq=0;
00293   s->sgram = (Complex**) malloc( N_time*sizeof(Complex*) );
00294   for( i=0; i<N_time; i++ ){
00295      s->sgram[i] = (Complex*) malloc( N_freq*sizeof(Complex) );
00296   }
00297   return s;
00298 }
00299 
00302 void spectrogram_free( Spectrogram *s ){
00303   int i;
00304 
00305   for( i=0; i<s->N_time;  i++ ){
00306      free( s->sgram[i] );
00307   }
00308   free( s->sgram );
00309   free( s );
00310 }
00311 
00312 /*----------------- WINDOW-FUNCTIONS ------------------ */
00313 
00323 Array* window_dirichlet(  int n, double noparam ){
00324   int i;
00325 
00326   if( !ISODD( n ) ){
00327      errprintf("window size must be ODD! Adding 1, n=%i!\n", n+1);
00328      n++;
00329   }
00330   Array *window = array_new2( DOUBLE, 1, n );
00331   for( i=0; i<n; i++ ){
00332      vec_IDX( window,i ) = 1.0;
00333   }
00334 
00335   return window;
00336 }
00337 
00349 Array* window_gaussian( int n, double sigma ){
00350   int i;
00351 
00352   if( !ISODD( n ) ){
00353      errprintf("window size must be ODD! Adding 1, n=%i!\n", n+1);
00354      n++;
00355   }
00356 
00357   Array *window = array_new2( DOUBLE, 1, n );
00358   for( i=0; i<n; i++ ){
00359      vec_IDX(window,i) = exp(-0.5*SQR( (i-(n-1)/2.0)/(double)(sigma*(n-1)/2.0)) );
00360   }
00361 
00362   return window;
00363 }
00364 
00374 Array* window_hamming( int n, double noparam ){
00375   int i;
00376 
00377   if( !ISODD( n ) ){
00378      errprintf("window size must be ODD! Adding 1, n=%i!\n", n+1);
00379      n++;
00380   }
00381 
00382   Array *window = array_new2( DOUBLE, 1, n );
00383   for( i=0; i<n; i++ ){
00384      vec_IDX(window,i) =  0.53836 - 0.46164*cos( (2* PI *i)/(double)(n-1) );
00385   }
00386 
00387   return window;
00388 }
00399 Array* window_hanning( int n, double noparam ){
00400   int i;
00401 
00402   if( !ISODD( n ) ){
00403      errprintf("window size must be ODD! Adding 1, n=%i!\n", n+1);
00404      n++;
00405   }
00406   Array *window = array_new2( DOUBLE, 1, n );
00407   for( i=0; i<n; i++ ){
00408      vec_IDX( window,i) =  0.5*(1 - cos( (2* PI *i)/(double)(n-1) ));
00409   }
00410 
00411   return window;
00412 }
00413 
00414 
00423 Array* window_kaiser( int n, double alpha ){
00424   int i;
00425   double bessel_alpha;
00426 
00427   Array *window = array_new2( DOUBLE, 1, n );
00428 
00429   bessel_alpha=gsl_sf_bessel_I0( alpha );
00430   for( i=0; i<n-1; i++ ){
00431      vec_IDX(window,i) = gsl_sf_bessel_I0( alpha*sqrt(1 - SQR( (2*i)/(double)(n-1) - 1  ) ) ) / bessel_alpha;
00432   }
00433   vec_IDX(window,n-1)=0;
00434 
00435   return window;
00436 }
00437 

Generated on Fri Jun 25 2010 14:10:21 for libeegtools by  doxygen 1.7.0