File indexing completed on 2024-12-22 04:18:10
0001 /*************************************************************************** 0002 * * 0003 * copyright : (C) 2007 The University of Toronto * 0004 * netterfield@astro.utoronto.ca * 0005 * copyright : (C) 2005 University of British Columbia * 0006 * dscott@phas.ubc.ca * 0007 * * 0008 * This program is free software; you can redistribute it and/or modify * 0009 * it under the terms of the GNU General Public License as published by * 0010 * the Free Software Foundation; either version 2 of the License, or * 0011 * (at your option) any later version. * 0012 * * 0013 ***************************************************************************/ 0014 0015 /* 0016 * Generic pass filter plugin for KST. 0017 * Released under the terms of the GPL 0018 */ 0019 0020 #ifndef FILTERS_H 0021 #define FILTERS_H 0022 0023 #include <stdlib.h> 0024 #include <math.h> 0025 #include <string.h> 0026 #include <gsl/gsl_errno.h> 0027 #include <gsl/gsl_fft_real.h> 0028 #include <gsl/gsl_fft_halfcomplex.h> 0029 0030 #include "vector.h" 0031 #include "scalar.h" 0032 0033 double filter_calculate( double dFreqValue, Kst::ScalarList scalars ); 0034 int min_pad(Kst::ScalarList scalars); 0035 0036 void fit_mb(double *y, int n, double &m, double &b) { 0037 if (n<5) { 0038 m = 0.0; 0039 b = y[0]; 0040 return; 0041 } 0042 0043 double Sy=0; 0044 double x_ = 0; // mean of x 0045 double y_ = 0; // mean of y 0046 int i; 0047 double x; 0048 double Sdxdy=0; // sum(x - x_) 0049 double Sdx2=0; // sum((x - x_)^2) 0050 0051 for (i = 0; i<n; i++) { 0052 Sy += y[i]; 0053 } 0054 x_ = double(n)*0.5; 0055 y_ = Sy/n; 0056 0057 for (i = 0; i<n; i++) { 0058 x = i; 0059 Sdxdy += (x - x_) * (y[i] - y_); 0060 Sdx2 += (x - x_) * (x - x_); 0061 } 0062 Sdx2 = qMax(Sdx2,1.0); 0063 m = Sdxdy/Sdx2; 0064 b = y_; 0065 } 0066 0067 bool kst_pass_filter( 0068 Kst::VectorPtr vector, 0069 Kst::ScalarList scalars, 0070 Kst::VectorPtr outVector) { 0071 0072 gsl_fft_real_wavetable* real; 0073 gsl_fft_real_workspace* work; 0074 gsl_fft_halfcomplex_wavetable* hc; 0075 double* pPadded; 0076 double dFreqValue; 0077 int iLengthData; 0078 int iLengthDataPadded; 0079 bool bReturn = false; 0080 int iStatus; 0081 int i; 0082 0083 if( scalars.at(1)->value() > 0.0 ) { 0084 iLengthData = vector->length(); 0085 0086 if( iLengthData > 0 ) { 0087 // 0088 // round up to the nearest power of 2... 0089 // 0090 iLengthDataPadded = (int)pow( 2.0, ceil( log10( (double)iLengthData ) / log10( 2.0 ) ) ); 0091 // make sure the padding is long enough - this depends on the type of filter. 0092 if (iLengthDataPadded - iLengthData < min_pad(scalars)) { 0093 //qDebug() << "doubled length" << min_pad(scalars) << iLengthDataPadded - iLengthData << iLengthDataPadded; 0094 iLengthDataPadded *= 2.0; 0095 } 0096 pPadded = (double*)malloc( iLengthDataPadded * sizeof( double ) ); 0097 if( pPadded != 0L ) { 0098 outVector->resize(iLengthData); 0099 //outVector->resize(iLengthDataPadded); // DEBUG ************ 0100 0101 real = gsl_fft_real_wavetable_alloc( iLengthDataPadded ); 0102 if( real != NULL ) { 0103 work = gsl_fft_real_workspace_alloc( iLengthDataPadded ); 0104 if( work != NULL ) { 0105 memcpy( pPadded, vector->noNanValue(), iLengthData * sizeof( double ) ); 0106 0107 // We are going to do a cubic spline extrapolation on the data 0108 // to improve behavior for high pass filters. 0109 double m1, b1; 0110 double m2, b2; 0111 0112 int nf = min_pad(scalars)/10.0; 0113 if (nf > iLengthData/5) nf = iLengthData/5; 0114 0115 fit_mb(pPadded, nf, m2, b2); 0116 fit_mb(pPadded + (iLengthData-nf-1), nf, m1, b1); 0117 0118 double a = b1; 0119 double b = m1; 0120 double X = double(nf + iLengthDataPadded - iLengthData); 0121 double d = (-2.0*b2 +m2*X + 2.0*b1 + m1*X)/(X*X*X); 0122 double c = (b2 - b1 - m1*X - d*X*X*X)/(X*X); 0123 0124 // 0125 // polynomial extrapolation on the padded values... 0126 // 0127 for( i=iLengthData; i<iLengthDataPadded; i++ ) { 0128 X = double(i-iLengthData)+nf*0.5; 0129 //pPadded[i] = a + b*X + c*X*X + d*X*X*X; 0130 pPadded[i] = a + X*(b + X*(c + X*d)); 0131 //pPadded[i] = vector->value()[iLengthData-1] - (double)( i - iLengthData + 1 ) * ( vector->value()[iLengthData-1] - vector->value()[0] ) / (double)( iLengthDataPadded - iLengthData ); 0132 } 0133 0134 // 0135 // calculate the FFT... 0136 // 0137 iStatus = gsl_fft_real_transform( pPadded, 1, iLengthDataPadded, real, work ); 0138 0139 if( !iStatus ) { 0140 // 0141 // apply the filter... 0142 // 0143 for( i=0; i<iLengthDataPadded; i++ ) { 0144 dFreqValue = 0.5 * (double)i / (double)iLengthDataPadded; 0145 pPadded[i] *= filter_calculate( dFreqValue, scalars ); 0146 } 0147 0148 hc = gsl_fft_halfcomplex_wavetable_alloc( iLengthDataPadded ); 0149 if( hc != NULL ) { 0150 // 0151 // calculate the inverse FFT... 0152 // 0153 iStatus = gsl_fft_halfcomplex_inverse( pPadded, 1, iLengthDataPadded, hc, work ); 0154 if( !iStatus ) { 0155 memcpy( outVector->raw_V_ptr(), pPadded, iLengthData * sizeof( double ) ); 0156 //memcpy( outVector->raw_V_ptr(), pPadded, iLengthDataPadded * sizeof( double ) ); // DEBUG ********************** 0157 bReturn = true; 0158 } 0159 gsl_fft_halfcomplex_wavetable_free( hc ); 0160 } 0161 } 0162 gsl_fft_real_workspace_free( work ); 0163 } 0164 gsl_fft_real_wavetable_free( real ); 0165 } 0166 free( pPadded ); 0167 } 0168 } 0169 } 0170 return bReturn; 0171 } 0172 0173 #endif