bpmprocess/fit_waveform.c

Go to the documentation of this file.
00001 
00005 #include <bpm/bpm_nr.h>
00006 #include <bpm/bpm_alloc.h>
00007 #include <bpm/bpm_messages.h>
00008 #include <bpm/bpm_process.h>
00009 
00010 #define FIT_MAX_ITER 10000
00011 
00012 #define FIT_AMP          0
00013 #define FIT_PHASE        1
00014 #define FIT_FREQ         2
00015 #define FIT_TDECAY       3
00016 
00017 #define FIT_T0           0
00018 #define FIT_FS           1
00019 
00020 void fcnwfjac( double* par, double *jac, int npars, int ns, void *a ) {
00021   int i, j;
00022   double t, sinarg, exparg, cosarg;
00023 
00024   // we trust we have npars = 4 here !!
00025 
00026   for( i=j=0; i<ns; i++ ) {
00027     sample_to_time( ( (double*)a )[FIT_FS], ns, i, &t );
00028     if ( t >=  ((double*)a)[FIT_T0] ) {
00029       sinarg = sin( 2.*PI*par[FIT_FREQ]* ( t - ((double*)a)[FIT_T0] ) + par[FIT_PHASE] );
00030       cosarg = cos( 2.*PI*par[FIT_FREQ]* ( t - ((double*)a)[FIT_T0] ) + par[FIT_PHASE] );
00031       exparg = exp( -( t - ((double*)a)[FIT_T0] )  / par[FIT_TDECAY] );
00032       
00033       // these have to be in order of appearance :)
00034 
00035       // \partial x / \partial p0 (amp)
00036       jac[j++] = exparg * sinarg;
00037 
00038       // \partial x / \partial p1 (phase)
00039       jac[j++] = par[FIT_AMP] * exparg * cosarg; 
00040 
00041       // \partial x / \partial p2 (freq)
00042       jac[j++] = par[FIT_AMP] * exparg * cosarg * 2.*PI*( t - ((double*)a)[FIT_T0] );
00043 
00044       // \partial x / \partial p3 (tdecay)
00045       jac[j++] = par[FIT_AMP] * exparg * (t - ((double*)a)[FIT_T0])/SQR( par[FIT_TDECAY]) * sinarg;
00046       
00047     } else {
00048       jac[j++] = 0.;
00049       jac[j++] = 0.;
00050       jac[j++] = 0.;
00051       jac[j++] = 0.;
00052     }
00053     
00054   }
00055 }
00056 
00062 void fcnwf( double* par, double *sinwf, int npars, int ns, void *a ) {
00063 
00064   double t;
00065   int i;
00066 
00067   for( i=0; i<ns; i++ ) {
00068     sample_to_time( ( (double*)a )[FIT_FS], ns, i, &t );
00069     if ( t >=  ( (double*)a )[FIT_T0] ) {
00070       sinwf[i] = par[FIT_AMP] 
00071         * exp( - ( t-( (double*)a )[FIT_T0]) / par[FIT_TDECAY] ) 
00072         * sin( 2.*PI*par[FIT_FREQ]*(t-( (double*)a )[FIT_T0]) + par[FIT_PHASE] );
00073     } else {
00074       sinwf[i] = 0.;
00075     }
00076   }
00077 
00078   return;
00079 }
00080 
00081 
00101 int fit_waveform( int *wf, int ns, double t0, double fs, 
00102                   double i_freq, double i_tdecay, double i_amp, double i_phase,
00103                   double *freq, double *tdecay, double *amp, double *phase ) {
00104 
00105   double *yval, a[2], ped, rms;
00106   const int npars = 4;
00107   double par[npars]; // 4 parameters in fit : amp, phase, freq, tdecay
00108   double opt[4], info[LM_INFO_SZ];
00109   int i;
00110 
00111   double err[256];
00112 
00113   opt[0]=LM_INIT_MU; opt[1]=1E-15; opt[2]=1E-15; opt[3]=1E-20;
00114 
00115   if ( ! wf ) {
00116     bpm_error( "Invalid waveform pointer in fit_waveform(...)",
00117                __FILE__, __LINE__ );
00118     return BPM_FAILURE;
00119   }
00120   
00121   // need a double array
00122   yval = alloc_simple_wave_double( ns );
00123   if ( ! yval ) {
00124     bpm_error( "Unable to allocate memory for waveform in fit_waveform(...)",
00125                __FILE__, __LINE__ );
00126     return BPM_FAILURE;
00127   }
00128 
00129   // subtract pedestal first
00130   if ( get_pedestal( wf, ns, 20, &ped, &rms ) == BPM_FAILURE ) {
00131     bpm_error( "Error getting pedestal in fit_waveform(...)", __FILE__, __LINE__  );
00132     free_simple_wave_double( yval );
00133     return BPM_FAILURE;
00134   }
00135 
00136   // preparing
00137   a[FIT_T0] = t0;
00138   a[FIT_FS] = fs;
00139   for ( i=0; i<ns; i++ ) {
00140     yval[i] = (double) wf[i] - ped;
00141   }
00142   par[FIT_AMP]    = i_amp;
00143   par[FIT_PHASE]  = i_phase;
00144   par[FIT_FREQ]   = i_freq;
00145   par[FIT_TDECAY] = i_tdecay;
00146   
00147   // we've calculated the jacobian analytically, so let's use it !
00148   nr_lmder( fcnwf, fcnwfjac, par, yval, npars, ns, FIT_MAX_ITER, opt, info, NULL, NULL, a );
00149 
00150   /*
00151     TODO :
00152     - Probably need to put in some box constraints for better behaviour at a certain point, 
00153       can use the routine nr_lmder_bc for this. 
00154     - Maybe program in something to replace the matrix inversion based upon the LU algorithm
00155       in nr_levmar.c. The original version had some LAPACK functionality, but as we
00156       wanted this standalone, i've cut it out. 
00157     - Best way to use it probably to take the parameters from previous fit of last pulse and have
00158       them as initials for the current fit.
00159   */
00160 
00161 
00162   *amp    = par[FIT_AMP];
00163   *phase  = par[FIT_PHASE];
00164   *freq   = par[FIT_FREQ];
00165   *tdecay = par[FIT_TDECAY];
00166 
00167   free_simple_wave_double( yval );
00168 
00169   return BPM_SUCCESS;
00170 }
00171 
00172 #undef FIT_MAX_ITER
00173 #undef FIT_AMP      
00174 #undef FIT_PHASE    
00175 #undef FIT_FREQ     
00176 #undef FIT_TDECAY   
00177 #undef FIT_T0       
00178 #undef FIT_FS
00179 

Generated on Thu Jan 10 10:18:04 2008 for libbpm by  doxygen 1.5.1